いつ使う?
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
キーワード引数使うと、スッキリ書けて気持ちがいい。