スポンサーリンク

2015年8月21日

[Rails Tutorial for Phoenix]View 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

リファクタリング第二弾。
今度は、ビューに関連する部分をリファクタリングしていきます。

Index

View refactoring
|> To use in common the function (LayoutView.current_user/1)
|> Modification of function (UserView.current_user/2)
|> Create gravator module
|> Create pagination view module

To use in common the function. (LayoutView.current_user/1)

LayoutView.current_user/1をuser_viewでも使いたい場面がありました。
その時は、show.html.eexにてconnから直接、現在のユーザを取得していましたね。
LayoutViewに関数があるのに使わないのは勿体ないです。
しかし、別のビューから関数を呼ぶのは分かり辛くなります。
なので、対象の関数を共通で使えるようします。

ファイル: lib/helpers/view_helper.ex

新しくビューを補助するモジュールを作成。
defmodule SampleApp.Helpers.ViewHelper do
  def current_user(conn) do
    conn.assigns[:current_user]
  end
end

ファイル: web/web.ex

それぞれのモジュールでインポートしてもいいのですが、
web.exで全ビューに対して一括でインポートさせます。
def view do
  quote do
    ...

    # My view helper
    import SampleApp.Helpers.ViewHelper
  end
end

ファイル: web/views/layout_view.ex

以下の関数をLayoutViewから削除して下さい。
  • current_user/1

ファイル: web/templates/user/show.html.eex

修正前:
<%= if !current_user?(@conn, @user) do %>
  <%= if !following?(@conn, @user.id) do %>
    <%= form_tag(relationship_path(@conn, :create), method: :post) %>
      <input type="hidden" name="id" value="<%= @conn.assigns[:current_user].id %>">
      <input type="hidden" name="follow_id" value="<%= @user.id %>">
      <%= submit "Follow", class: "btn btn-primary" %>
    </form>
  <% else %>
    <%= form_tag(relationship_path(@conn, :delete, @conn.assigns[:current_user]), method: :delete) %>
      <input type="hidden" name="unfollow_id" value="<%= @user.id %>">
      <%= submit "Unfollow", class: "btn btn-primary" %>
    </form>
  <% end %>
<% end %>
修正後:
<%= if !current_user?(@conn, @user) do %>
  <%= if !following?(@conn, @user.id) do %>
    <%= form_tag(relationship_path(@conn, :create), method: :post) %>
      <input type="hidden" name="id" value="<%= current_user(@conn).id %>">
      <input type="hidden" name="follow_id" value="<%= @user.id %>">
      <%= submit "Follow", class: "btn btn-primary" %>
    </form>
  <% else %>
    <%= form_tag(relationship_path(@conn, :delete, current_user(@conn)), method: :delete) %>
      <input type="hidden" name="unfollow_id" value="<%= @user.id %>">
      <%= submit "Unfollow", class: "btn btn-primary" %>
    </form>
  <% end %>
<% end %>

Modification of function (UserView.current_user/2)

UserView.current_user/2の処理と場所を変更します。

ファイル: lib/helpers/view_helper.ex

以下の関数を追加して下さい。
def current_user?(conn, %SampleApp.User{id: id}) do
  user = SampleApp.Repo.get(SampleApp.User, id)
  conn.assigns[:current_user] == user
end

ファイル: web/views/user_view.ex

以下の関数をUserViewから削除して下さい。
  • current_user?/2

Create gravator module

Gravator用のモジュールを作成します。

ファイル: lib/gravator.ex

defmodule SampleApp.Gravator do

  def get_gravatar_url(email, size) do
    gravatar_id = email_to_gravator_id(email)
    "https://secure.gravatar.com/avatar/#{gravatar_id}?s=#{size}"
  end

  defp email_to_gravator_id(email) do
    email |> email_downcase |> email_crypt_md5
  end

  defp email_crypt_md5(email) do
    :erlang.md5(email)
    |> :erlang.bitstring_to_list
    |> Enum.map(&(:io_lib.format("~2.16.0b", [&1])))
    |> List.flatten
    |> :erlang.list_to_bitstring
  end

  defp email_downcase(email) do
    String.downcase(email)
  end
end

ファイル: web/views/user_view.ex

以下の関数をUserViewから削除して下さい。
  • email_crypt_md5/1
  • email_downcase/1
また、以下のように関数の修正をして下さい。
修正前:
def get_gravatar_url(%User{email: email}) do
  gravatar_id = email |> email_downcase |> email_crypt_md5
  "https://secure.gravatar.com/avatar/#{gravatar_id}?s=50"
end
修正後:
def get_gravatar_url(%User{email: email}) do
  SampleApp.Gravator.get_gravatar_url(email, 50)
end

Create pagination view module

ページネーション用のビューモジュールを作成します。

ファイル: web/views/pagination_view.ex

defmodule SampleApp.PaginationView do
  use SampleApp.Web, :view

  def get_previous_page_url(action, current_page) do
    get_page_url(action, current_page - 1)
  end

  def get_next_page_url(action, current_page) do
    get_page_url(action, current_page + 1)
  end

  def get_page_url(action, page_number) do
    "#{action}?select_page=#{page_number}"
  end
end

ファイル: web/templates/user/pagination.html.eex

pagination.html.eexファイルを以下のように移動します。
変更前: web/templates/user/pagination.html.eex
変更後: web/templates/pagination/pagination.html.eex

ファイル: web/views/user_view.ex

以下の関数をUserViewから削除して下さい。
  • get_previous_page_url/2
  • get_next_page_url/2
  • get_page_url/2
ページネーションの呼び出し部分を変更します。

ファイル: web/templates/user/index.html.eex

変更前:
<%= if !is_empty_list?(@users) do %>
  <%= render "pagination.html",
             action: user_path(@conn, :index),
             current_page: @current_page,
             page_list: @page_list,
             total_pages: @total_pages %>

  ...

  <%= render "pagination.html",
             action: user_path(@conn, :index),
             current_page: @current_page,
             page_list: @page_list,
             total_pages: @total_pages %>

<% end %>
変更後:
<%= if !is_empty_list?(@users) do %>
  <%= render SampleApp.PaginationView, "pagination.html",
             action: user_path(@conn, :index),
             current_page: @current_page,
             page_list: @page_list,
             total_pages: @total_pages %>

  ...

  <%= render SampleApp.PaginationView, "pagination.html",
             action: user_path(@conn, :index),
             current_page: @current_page,
             page_list: @page_list,
             total_pages: @total_pages %>

<% end %>

ファイル: web/templates/user/show.html.eex

変更前:
<div style="clear: right; margin-left: 250px;">
  <h2>Microposts</h2>

  ...

    <%= render "pagination.html",
               action: user_path(@conn, :show, @user),
               current_page: @current_page,
               page_list: @page_list,
               total_pages: @total_pages %>
  <% end %>
</div>
変更後:
<div style="clear: right; margin-left: 250px;">
  <h2>Microposts</h2>

  ...

    <%= render SampleApp.PaginationView, "pagination.html",
               action: user_path(@conn, :show, @user),
               current_page: @current_page,
               page_list: @page_list,
               total_pages: @total_pages %>
  <% end %>
</div>

ファイル: web/templates/user/show_follow.html.eex

変更前:
<div style="clear: right; margin-left: 250px;">
  <%= if @users do %>
    ...

    <%= render "pagination.html",
             action: @action,
             current_page: @current_page,
             page_list: @page_list,
             total_pages: @total_pages %>
  <% end %>
</div>
変更後:
<div style="clear: right; margin-left: 250px;">
  <%= if @users do %>
    ...

    <%= render SampleApp.PaginationView, "pagination.html",
             action: @action,
             current_page: @current_page,
             page_list: @page_list,
             total_pages: @total_pages %>
  <% end %>
</div>

Speaking to oneself

これでUserViewは大分すっきりしたかな?
次はちょっと面倒ですけど、
テンプレートの共通している部分を細かく分割していこうか・・・
変更点の一覧については以下のリンク先にあります。
変更点: Github - darui00kara/phoenix_tutorial (View refactoring)

Bibliography

特になし

人気の投稿