LoginSignup
4
2

More than 5 years have passed since last update.

ActionPack Variantsで、layoutとviewファイルに同じ適応をさせる

Last updated at Posted at 2016-11-25

ActionPack Variantsでは、request.variantに値を入れると入れた値を元にしてviewファイルを探してくれます。

今回、スマホ対応にこの機能を使おうとしたのですが、スマホレイアウトを用意して、一部のviewにスマホ用を用意しても、対応していない方もスマホ用のレイアウトが適応されてしまうので、全部用意する必要がでてきました。

app/views/layouts/articles.html+mobile.erb
app/views/layouts/articles.html.erb
app/views/articles/index.html+mobile.erb
app/views/articles/index.html.erb
app/views/articles/show.html.erb

こんなファイル構成だと/articles/index でlayouts/articles.html+mobile.erbが適応されるのは嬉しいのですが、articles/showでlayouts/articles.html+mobile.erbを適応すると崩れてしまうので、PG的に回避したかったのです。

というわけで、以下の様なmodlueを作りました


app/controllers/concerns/mobile_render.rb
# Rails 4.2 使用
module ActionView class LookupContext
    register_detail(:variants_use) { []}
  end
  class TemplateRenderer
    def render_template(template, layout_name = nil, locals = nil) #:nodoc:
      view, locals = @view, locals || {}
      if defined?(template.variants) && template.variants
        @lookup_context.variants_use << template.variants
      end
      render_with_layout(layout_name, locals) do |layout|
        instrument(:template, :identifier => template.identifier, :layout => layout.try(:virtual_path)) do
          template.render(view, locals) { |*name| view._layout_for(*name) }
        end
      end
    end
  end
end

module MobileRender
  def _default_layout(require_layout = false)
    lookup_context.variants_use = lookup_context.variants_use.flatten.uniq
    variants = []
    lookup_context.variants.delete_if{ | variant | ! lookup_context.variants_use.include?(variant.to_s) }
    super(require_layout)
  end
end

render時に、templateを呼び出した時、templateで使ったvariantsを取得して、variants_useに格納し、レイアウトを呼び出す際にvariants_useにないものをvariantsから削除するという方法を取っています。

もし、別アプローチでの実現方法や、コード上の問題がありましたらご指摘頂けますと助かります。

[20170831追記]
@yasaichi さんのコメントより
以下の方法の方がスッキリしました。

module ActionViewTemplateRendererPatch
  def render_template(template, layout_name = nil, locals = nil)
    @lookup_context.variants = nil if template.variants == [nil]
    super
  end
end

ActionView::TemplateRenderer.prepend(ActionViewTemplateRendererPatch)
4
2
1

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
4
2