スポンサーリンク

2015年8月30日

[Rails Tutorial for Phoenix]Last refactoring

Goal

細かい部分のリファクタリングを実施する。

Dev-Environment

OS: Windows8.1
Erlang: Eshell V6.4, OTP-Version 17.5
Elixir: v1.0.4
Phoenix Framework: v0.13.1
PostgreSQL: postgres (PostgreSQL) 9.4.4

Wait a minute

Phoenix Tutorialのリファクタリング第四弾。
最後のリファクタリングです。

Index

Last refactoring
|> Create encrypt module
|> Unification of wording
|> Create sign-in module
|> Error message at the time of user registration
|> Delete button of Micropost
|> Extra

Create encrypt module

Userモデルから暗号化する関数を分離します。

ファイル: lib/encryption.ex

新しく暗号化を担当するモジュールを作成します。
defmodule SampleApp.Encryption do
  # password decrypt
  def decrypt(password) do
    Safetybox.decrypt(password)
  end

  # password encrypt
  def encrypt(password) do
    Safetybox.encrypt(password, :default)
  end
end

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

以下の関数を削除して下さい。
  • decrypt/1
  • encrypt/1
Encryptionモジュールを使用するように修正して下さい。
修正前:
def set_password_digest(changeset) do
  password = Ecto.Changeset.get_field(changeset, :password)
  change(changeset, %{password_digest: encrypt(password)})
end
修正後:
def set_password_digest(changeset) do
  password = Ecto.Changeset.get_field(changeset, :password)
  change(changeset, %{password_digest: SampleApp.Encryption.encrypt(password)})
end

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

Encryptionモジュールを使用するように修正して下さい。
修正前:
def edit(conn, %{"id" => id}) do
  user = Repo.get(SampleApp.User, id)
  user = Map.put(user, :password, SampleApp.User.decrypt(user.password_digest))
  changeset = SampleApp.User.changeset(user)

  render(conn, "edit.html", user: user, changeset: changeset)
end
修正後:
def edit(conn, %{"id" => id}) do
  user = Repo.get(SampleApp.User, id)
  user = Map.put(user, :password, SampleApp.Encryption.decrypt(user.password_digest))
  changeset = SampleApp.User.changeset(user)

  render(conn, "edit.html", user: user, changeset: changeset)
end

Unification of wording

ログイン / ログアウト、サインイン / サインアウトと統一していない文言を使用しています。
サインインの方へ統一します。

ファイル: web/templates/session/login_form.html

ファイル名の変更。
修正前: login_form.html.eex
修正後: signin_form.html.eex
パラメータ名の変更。
修正前:
<%= form_for @conn, session_path(@conn, :create), [name: :login_params], fn f -> %>
修正後:
<%= form_for @conn, session_path(@conn, :create), [name: :signin_params], fn f -> %>

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

使用するテンプレート名を修正。
修正前:
def new(conn, _params) do
  render conn, login_form.html"
end
修正後:
def new(conn, _params) do
  render conn, "signin_form.html"
end
パラメータ名と文言の修正。
修正前:
def create(conn, %{"login_params" => %{"email" => email, "password" => password}}) do
  case login(email, password) do
    {:ok, user} ->
      conn
      |> put_flash(:info, "User login is success!!")
      |> put_session(:user_id, user.id)
      |> redirect(to: static_pages_path(conn, :home))
    :error ->
      conn
      |> put_flash(:error, "User login is failed!! email or password is incorrect.")
      |> redirect(to: session_path(conn, :new))
  end
end
修正後:
def create(conn, %{"signin_params" => %{"email" => email, "password" => password}}) do
  case sign_in(email, password) do
    {:ok, user} ->
      conn
      |> put_flash(:info, "User sign-in is success!!")
      |> put_session(:user_id, user.id)
      |> redirect(to: static_pages_path(conn, :home))
    :error ->
      conn
      |> put_flash(:error, "User sign-in is failed!! email or password is incorrect.")
      |> redirect(to: session_path(conn, :new))
  end
end
flashのメッセージを修正。
修正前:
def delete(conn, _params) do
  conn
  |> put_flash(:info, "Logout now! See you again!!")
  |> delete_session(:user_id)
  |> redirect(to: static_pages_path(conn, :home))
end
修正後:
def delete(conn, _params) do
  conn
  |> put_flash(:info, "Sign-out now! See you again!!")
  |> delete_session(:user_id)
  |> redirect(to: static_pages_path(conn, :home))
end
関数名を修正。
修正前:
defp login(email, password) do
  ...
end
修正後:
defp sign_in(email, password) do
  ...
end
Safetyboxの部分で、Encryptionを使うように修正。
修正前:
defp authentication(user, password) do
  case user do
    nil -> false
      _ ->
        password == Safetybox.decrypt(user.password_digest)
  end
end
修正後:
defp authentication(user, password) do
  case user do
    nil -> false
      _ ->
        password == SampleApp.Encryption.decrypt(user.password_digest)
  end
end

Create sign-in module

Sessionコントローラのサインインを分離します。

ファイル: lib/sing_in_action.ex

新しくサインインを行うモジュールを作成します。
defmodule SampleApp.Signin do
  import SampleApp.Authentication

  def sign_in(email, password) do
    user = SampleApp.User.find_user_from_email(email)
    case authentication(user, password) do
      true -> {:ok, user}
         _ -> :error
    end
  end
end
Sessionコントローラの認証を分離します。

ファイル: lib/authentication.ex

新しく認証を行うモジュールを作成します。
defmodule SampleApp.Authentication do
  def authentication(user, password) do
    case user do
      nil -> false
        _ ->
          password == SampleApp.Encryption.decrypt(user.password_digest)
    end
  end
end

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

以下の関数を削除します。
  • sign_in/2
  • authentication/2
importを追加します。
import SampleApp.Signin

Error message at the time of user registration

新しくユーザを登録する時に、エラーメッセージが発生していますね。
これを修正します。

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

新しく関数を作成。
def new do
  %SampleApp.User{} |> cast(:empty, @required_fields, @optional_fields)
end

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

作成した関数を使用するように、newアクションを修正します。
修正前:
def new(conn, _params) do
  changeset = SampleApp.User.changeset(%SampleApp.User{})
  render(conn, "new.html", changeset: changeset)
end
修正後:
def new(conn, _params) do
  render(conn, "new.html", changeset: SampleApp.User.new)
end

Delete button of Micropost

自分自身の投稿以外は削除できないようにします。

ファイル: web/templates/shared/microposts.html.eex

表示中のユーザidとマイクロポストのユーザidの比較を追加しました。
修正前:
<ol class="microposts">
  <li>
  <%= for post <- @posts do %>
    <span class="content"><%= post.content %></span>
    <span class="timestamp">
      Posted <%= post.inserted_at %> ago.
    </span>
    <%= link "Delete", to: micropost_path(@conn, :delete, post), method: :delete, class: "btn btn-danger btn-xs" %>
  <% end %>
  </li>
</ol>
修正後:
<ol class="microposts">
  <li>
  <%= for post <- @posts do %>
    <span class="content"><%= post.content %></span>
    <span class="timestamp">
      Posted <%= post.inserted_at %> ago.
    </span>
    <%= if @user.id == post.user_id do %>
      <%= link "Delete", to: micropost_path(@conn, :delete, post), method: :delete, class: "btn btn-danger btn-xs" %>
    <% end %>
  <% end %>
  </li>
</ol>

Extra

ページネーションのリファクタリングをした時に修正を忘れていました。

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

Micropostコントローラで、リダイレクト先を指定を修正します。
createアクションの修正。
修正前:
def create(conn, %{"micropost" => micropost_params}) do
  ...

  action = "#{user_path(conn, :show, conn.assigns[:current_user].id)}?select_page=1"
  redirect(conn, to: action)
end
修正後:
def create(conn, %{"micropost" => micropost_params}) do
  ...

  redirect(conn, to: user_path(conn, :show, conn.assigns[:current_user]))
end
deleteアクションの修正。
修正前:
def delete(conn, %{"id" => id}) do
  ...

  action = "#{user_path(conn, :show, conn.assigns[:current_user].id)}?select_page=1"

  conn
  |> put_flash(:info, "Micropost deleted successfully.")
  |> redirect(to: action)
end
修正後:
def delete(conn, %{"id" => id}) do
  ...

  conn
  |> put_flash(:info, "Micropost deleted successfully.")
  |> redirect(to: user_path(conn, :show, conn.assigns[:current_user]))
end

Speaking to oneself

リファクタリングをしようと思えば幾らでもできるのですが、
切りがないので、一旦これで終了します。
修正した方が良い部分などがありましたら、
ご一報頂けると助かります。
この後は、記事の修正をします。
全記事の書き直しだ~
変更点の一覧は以下のリンク先です。
Github: darui00kara/phoenix_tutorial - finish refactoring

Bibliography

特になし

人気の投稿