LoginSignup
2
2

More than 5 years have passed since last update.

render_if_present helper作った

Last updated at Posted at 2015-05-06

いつ使う?

RailsのViewで、特定の値が存在する時にのみpartialを表示したい場合、if文が出てくるとHTMLとしての見通しが悪くなって嫌だ!という時に役に立つんじゃないかと。
デフォルトの仕様として、メソッド名と同じpartialファイルを探索して、メソッド名と同じローカル変数に値をセットするので、規則に沿っておけばだいぶ短く書けるのがメリットです。

こういうケース

<% if @shop.page_design.shop_top_main_image.present? %>
  <%= render :shop_top_main_image, locals: { shop_top_main_image: @shop.page_design.shop_top_main_image } %>
<% end %>

Rubygemsに登録しました

ヘルパー => 家政婦 => kaseifu
今後も便利メソッドを追加していく予定。

J( 'ー`)し< ごめんくださいませー

使い方

基本形

<%= render_if_present :shop_top_main_image, in: @shop.page_design %>

partialファイルのパスを変えたいケース

partialファイルのパスのみを差し替える。

<%= render_if_present :shop_top_main_image, in: @shop.page_design, partial: '/shop/image' %>

共通のpartialファイルを使いたいケース

上記の例との違いは、partialファイルパスおよびローカル変数名の両方が、asで指定した値になる。partialと組み合わせれば、任意のpartialファイルパスを指定する事も可能。

<%= render_if_present :shop_top_main_image, in: @shop.page_design, as: :shop_image %>

localsを追加で渡したいケース

renderメソッドのlocalsと同じ。

<%= render_if_present :shop_top_main_image, in: @shop.page_design, locals: { shop_name: @shop.name } %>

コード

module ApplicationHelper
  # Render partial if the given method is present as the receiver's method.
  #
  # You can render only when @shop.page_design.shop_top_main_image is present.
  #   <%= render_if_present :shop_top_main_image, in: @shop.page_design %>
  # same as
  #   <% if @shop.page_design.shop_top_main_image.present? %>
  #     <%= render :shop_top_main_image, locals: { shop_top_main_image: @shop.page_design.shop_top_main_image } %>
  #   <% end %>
  #
  # You can pass different path of partial.
  #   <%= render_if_present :shop_top_main_image, in: @shop.page_design, partial: 'image' %>
  # same as
  #   <% if @shop.page_design.shop_top_main_image.present? %>
  #     <%= render :image, locals: { shop_top_main_image: @shop.page_design.shop_top_main_image } %>
  #   <% end %>
  #
  # You can use different name as a local variable name in the partial
  #   <%= render_if_present :shop_top_main_image, in: @shop.page_design, as: :shop_image %>
  # same as
  #   <% if @shop.page_design.shop_top_main_image.present? %>
  #     <%= render :shop_image, locals: { shop_image: @shop.page_design.shop_top_main_image } %>
  #   <% end %>
  #
  # You can pass more locals
  #   <%= render_if_present :shop_top_main_image, in: @shop.page_design, locals: { shop_name: @shop.name } %>
  # same as
  #   <% if @shop.page_design.shop_top_main_image.present? %>
  #     <%= render :shop_top_main_image, locals: { shop_top_main_image: @shop.page_design.shop_top_main_image, shop_name: @shop.name } %>
  #   <% end %>
  def render_if_present(method, in: nil, as: nil, **options)
    # "in" is special keyword so need to use local_variable_get to get value
    receiver = binding.local_variable_get(:in)

    raise ArgumentError, 'missing keyword: in' if receiver.nil?

    # If receiver doesn't respond to the given method, render nothing
    return '' unless receiver.respond_to?(method)

    key = (as || method).to_sym
    value = receiver.send(method)

    # If given method return blank, render nothing
    return '' if value.blank?

    # If partial file name is already exist use it else use key.
    options[:partial] ||= key.to_s

    options[:locals] ||= {}
    options[:locals].merge!(key => value)

    render options
  end
end

キーワード引数使うと、スッキリ書けて気持ちがいい。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2