読者です 読者をやめる 読者になる 読者になる

【Ruby】【Rails】RAILS ANTIPATTERNS、chapter3 viewのまとめ

目的

RAILS ANTIPATTERNSをのchapter3(view)の箇所を読んだのでまとめました。

Rails AntiPatterns: Best Practice Ruby on Rails Refactoring (Addison-Wesley Professional Ruby Series)

Rails AntiPatterns: Best Practice Ruby on Rails Refactoring (Addison-Wesley Professional Ruby Series)

PHPitis(PHPっぽくなりがち)

ドメインロジックとか複雑な表示ロジックとか、全部ビュー(app/viewsの下にあるファイル)に書かれがちだよねという話です。

解決策:View Helper勉強しよ!

詳しくは書かないけど、form_for, render, content_for, yield(:symbol) || 'default', content_for?について書かれていました。
form_forは本当にいろいろ使えてすごいのだけど、まだまだ使い切れていない感がある。
content_forの並びで言うと、provideもぜひ使いたいですね。

http://api.rubyonrails.org/classes/ActionView/Helpers/CaptureHelper.html#method-i-provide

解決策:いい感じにモデルにメソッド追加しよ!

以下のようなコードがあるとする。

<% if current_user &&
      (current_user == @post.user ||
      @post.editors.include?(current_user)) && @post.editable? &&
      @post.user.active? %>
  <%= link_to 'Edit this post', edit_post_url(@post) %>
<% end %>

これはモデルにメソッドを定義してあげて、view側は以下のような形にする。

<% if @post.editable_by?(current_user) %>
  <%= link_to 'Edit this post', edit_post_url(@post) %>
<% end %>

すっきり!

メソッドを定義する場所としては、まあまあ当たり前だけどコントローラで使う場合はモデル、そうじゃなければhelperに置くと書いてあった。

そのif文、helperに移動しよ!

app/views/alerts/index.html.erbが以下のようになっているとする。

<div class="feed">
  <% if @project %>
    <%= link_to "Subscribe to #{@project.name} alerts.", project_alerts_url(@project, :format => :rss), :class => "feed_link" %>
  <% else %>
    <%= link_to "Subscribe to these alerts.", alerts_url(format => :rss), :class => "feed_link" %>
  <% end %>
</div>

この場合はapp/helpers/alerts_helper.rbを作って以下のようにメソッドを追加する。(若干仕様変わってる?)

module AlertsHelper
  def rss_link(project = nil)
    link_to("Subscribe to these #{project.name if project} alerts.",
            alerts_rss_url(project),
            class: 'feed_link')
  end

  def alerts_rss_url(project = nil)
    if project
      project_alerts_url(project, format: :rss)
    else
      alerts_url(:rss)
    end
  end
end

view側のapp/views/alerts/index.html.erbは以下。

<div class="feed">
  <%= rss_link(@project) %>
</div>

いつも<div class="feed">が必要な場合は、content_tagを使ってhelperにうつしてしまってもいいとありました。
その場合はlink_toじゃなくてcontent_tag :aをあえて使ってもいいと書いてました。

ちょっとした感想

最後の、「helperに移動しよ!」的な話はいつも悩むところなのと、helperメソッドでcontent_tagをもりもり書くのなら、パーシャルでいいのでは?と思ったりします。
でも今回の= rss_link(@project)が、= render rss_link, project: @projectになるのはイマイチ感がありますね…なんでだろ。

viewにかかわらず、Railsはやりたいことを色んな方法で実装することができるので、一人で作っているときでさえ統一感がなくなることが有ります。rubocopで潰せるところはいいけど、自分が統一感を持って実装出来ているかどうかたまに振り返りながらすすめていきたいですね。