スポンサーリンク

2015年8月31日

[Rails Tutorial for Phoenix]Upgrade version of Phoenix-Framework

Goal

Phoenix-Frameworkをv1.0.0にバージョンアップします。

Dev-Environment

OS: Windows8.1
Erlang: Eshell V6.4, OTP-Version 17.5
Elixir: v1.0.5
Phoenix Framework: v0.13.1 → v1.0.0
PostgreSQL: postgres (PostgreSQL) 9.4.4
Safetybox: v0.1.2
Scrivener: v0.11.0

Wait a minute

Phoenix Tutorialのプロジェクトで使っている、
Phoenix-Frameworkのバージョンをv0.13.1からv1.0.0へバージョンアップします。
リリースノート調べてたけど・・・数多いな(笑)
まぁ、バージョンアップを放置していた自分の責任だな。
ここらで一気に解消します。

Index

Rails Tutorial for Phoenix
|> Preparation
|> Version-up
|> Reflection of the version-up content
|> Extra

Preparation

問題があっても、戻せるようにブランチを切っておきます。
>git checkout -b version_up
Switched to a new branch 'version_up'

>git branch
...
* version_up
準備良し!

Version-up

それでは、バージョンアップしましょう。
一気にバージョンアップをします。
そのためプロジェクトを新しく作成し、ソースコードを移行し、
ソースコードに必要なだけの変更をします。
>cd path/to/new/project

>mix phoenix.new sample_app
...

>mix ecto.create
...

>mix phoenix.server

Caution:

sample_appのDBは予め削除しておいて下さい。
同名プロジェクトで作成するとDB名が衝突します。
バージョンアップ自体は、
新しくプロジェクトを作成するだけで完了です。

Reflection of the version-up content

バージョンアップに伴う必要な変更を実施します。

ソースコードの移行を行う

移行対象のソースコード一覧。

マイグレーションファイル

  • priv/repo/migrations/[timestamp]_create_user.exs
  • priv/repo/migrations/[timestamp]_add_password_to_users.exs
  • priv/repo/migrations/[timestamp]_create_micropost.exs
  • priv/repo/migrations/[timestamp]_create_relationship.exs

静的ファイル

  • priv/static/css/custom.css

lib内に作成したファイル / ディレクトリ

  • lib/helpers (ディレクトリ)
  • lib/helpers/pagination_helper.ex
  • lib/helpers/validate_helper.ex
  • lib/helpers/view_helper.ex
  • lib/plugs (ディレクトリ)
  • lib/plugs/check_authentication.ex
  • lib/plugs/signed_in_user.ex
  • lib/authentication.ex
  • lib/encryption.ex
  • lib/gravator.ex
  • lib/sign_in.ex

Webサイト用のソースコード

Caution:

phoenix.newで生成されたソースコードは移行しません。

コントローラ

  • web/controllers/micropost_controller.ex
  • web/controllers/relationship_controller.ex
  • web/controllers/sesion_controller.ex
  • web/controllers/static_pages_controller.ex
  • web/controllers/user_controller.ex

モデル

  • web/models/micropost.ex
  • web/models/relationship.ex
  • web/models/user.ex

ビュー

  • web/views/pagination_view.ex
  • web/views/session_view.ex
  • web/views/shared_view.ex
  • web/views/static_pages_view.ex
  • web/views/user_view.ex

テンプレート

  • web/templates/layout/footer.html.eex
  • web/templates/layout/header.html.eex
  • web/templates/layout/shim.html.eex
  • web/templates/pagination/pagination.html.eex
  • web/templates/session/signin_form.html.eex
  • web/templates/shared/*.eex
  • web/templates/static_pages/*.eex
  • web/templates/user/*.eex

ソースコードへ同様の設定と変更の反映を行う

ファイル: mix.exs

利用していたライブラリを追加します。
defp deps do
  [...
   {:safetybox, "~> 0.1"},
   {:scrivener, "~> 1.0.0"}]
end
依存関係の解決を行います。
>mix deps.get

ファイル: web/router.ex

ルーティングの設定をします。
scope "/", SampleApp do
  pipe_through :browser # Use the default browser stack

  get "/", PageController, :index
  get "/signup", UserController, :new
  get "/home", StaticPagesController, :home
  get "/help", StaticPagesController, :help
  get "/about", StaticPagesController, :about
  get "/contact", StaticPagesController, :contact
  resources "/user", UserController, except: [:new]
  get "user/:id/following", UserController, :following
  get "user/:id/followers", UserController, :followers
  get "/signin", SessionController, :new
  post "/session", SessionController, :create
  get "/signout", SessionController, :delete
  resources "/post", MicropostController, only: [:create, :delete]
  resources "/relationship", RelationshipController, only: [:create, :delete]
end

ファイル: lib/sample_app/repo.ex

Scrivenerのuseを追加します。
defmodule SampleApp.Repo do
  use Ecto.Repo, otp_app: :sample_app
  use Scrivener, page_size: 10
end

ファイル: web/templates/layout/app.html

以下の通り編集しました。
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="">

    <title>Sample App!!</title>
    <link rel="stylesheet" href="<%= static_path(@conn, "/css/app.css") %>">
    <link rel="stylesheet" href="<%= static_path(@conn, "/css/custom.css") %>">

    <%= render "shim.html" %>
  </head>

  <body>
    <%= render "header.html", conn: @conn %>

    <div class="container">
      <%= @inner %>
    </div>

    <%= render "footer.html", conn: @conn %>

    <script src="<%= static_path(@conn, "/js/app.js") %>"></script>
  </body>
</html>

ファイル: web/models/user.ex

一意性の検証を行う関数が変わったようなので修正します。
def changeset(model, params \\ :empty) do
    model
    |> cast(params, @required_fields, @optional_fields)
    ...
    |> unique_constraint(:name)
    |> unique_constraint(:email)
    ...
  end
Description:
一意性の検証をするための関数が変わったようです。
ドキュメント: hexdocs - v1.0.1 Ecto - Changeset - unique_constraint/3
ドキュメントを読んでみると、
インデックスの作成が必要と記述されています。

ファイル: priv/repo/migration/[timestamp]_create_user.exs

インデックスを追加します。
defmodule SampleApp.Repo.Migrations.CreateUser do
  use Ecto.Migration
  @disable_ddl_transaction true

  def change do
    create table(:users) do
      add :name, :string
      add :email, :string

      timestamps
    end

    create index(:users, [:name], unique: true, concurrently: true)
    create index(:users, [:email], unique: true, concurrently: true)
  end
end
マイグレーションを行います。
>mix ecto.migrate
...

コントローラの以下の記述を削除

plug :action

ファイル: web/controllers/page_controller.ex

以下の記述を追加します。
plug SampleApp.Plugs.CheckAuthentication
後は、コンパイルと起動を実行してみて下さい。
(一通りの機能が使えたことは確認しています)
後は、ブランチをマージして削除したら終わりです。
>git checkout master
>git merge version_up
>git branch -d version_up

Extra

ちょっと修正するの忘れていた部分がありました。

ファイル: web/controllers/relationship_controller.ex

リダイレクト先をフォロー / アンフォローしたユーザページに変更します。
修正前:
def create(conn, params) do
  if SampleApp.Relationship.follow!(params["id"], params["follow_id"]) do
    conn = put_flash(conn, :info, "Follow successfully!!")
  else
    conn = put_flash(conn, :error, "Follow failed!!")
  end

  redirect(conn, to: static_pages_path(conn, :home))
end

def delete(conn, params) do
  SampleApp.Relationship.unfollow!(params["id"], params["unfollow_id"])

  conn
  |> put_flash(:info, "Unfollow successfully!!")
  |> redirect(to: static_pages_path(conn, :home))
end
修正後:
def create(conn, params) do
  if SampleApp.Relationship.follow!(params["id"], params["follow_id"]) do
    conn = put_flash(conn, :info, "Follow successfully!!")
  else
    conn = put_flash(conn, :error, "Follow failed!!")
  end

  redirect(conn, to: user_path(conn, :show, params["follow_id"]))
end

def delete(conn, params) do
  SampleApp.Relationship.unfollow!(params["id"], params["unfollow_id"])

  conn
  |> put_flash(:info, "Unfollow successfully!!")
  |> redirect(to: user_path(conn, :show, params["unfollow_id"]))
end

Speaking to oneself

一応、全部の設定は反映しているはずですが、
書き忘れている部分があるかもしれません。
もし、何かお気づきの点、変更が足りないなど、
ご指摘などありましたら、一報頂けると助かります。
本当は、少しずつバージョンアップした方がいいのは分かってるんですけど、
面倒くさかったんです。(後悔はしてない)

Bibliography

人気の投稿