Search code examples
ruby-on-railscachingseometa-tags

How to use Rails caches_action with layout:false and dynamically change meta tags?


I am stuck at what I think is a very simple/common usecase in a Rails web application. I want to use "caches_action, layout:false" and display, from the layout, dynamic tags that will be set by the action (either from the view or the controller).

I could not find any standard rails way to do this as content_for does not work with caches_action, instance variables are not cached (?), and the metatags helper gems that I have tried (metamagic and meta-tags) do not support this usecase.

Is there any way to do this ?

Example

I am using caches_action, layout:false on a SandboxController#show method

#app/controllers/sandbox_controller.rb
class SandboxController < ApplicationController

  caches_action :show, layout: false, expires_in: 1.minute

  def show
    @meta_title = "Best page ever"
    do_some_expensive_operation
  end

end

The view

#app/views/sandbox/show.html.erb
We are in show action.

The layout

#app/views/layouts/application.html.erb
<title><%= @meta_title %></title>
Debug: <%= @meta_title %> <br/>
<%= yield %>

Thanks !


Solution

  • I found a way to make it work, it's not as pretty as I would like it to be but it helps using caches_action and setting HTML meta tags from the view.

    Also, for the record, it seems that this was forgotten and buried deep down in the pipeline, as I did not find any recent mentions of this problem, only that caches_action and content_for together are not expected to work.

    Solution: I simply add a before_action to set the meta tags by using as less computation as possible.

    #app/controllers/sandbox_controller.rb
    class SandboxController < ApplicationController
    
      caches_action :show, layout: false, expires_in: 1.minute
      before_action :seo_show, only: :show
    
      def seo_show
        @meta_title = "Best page ever"
      end
    
      def show
        do_some_expensive_operation
      end
    
    end
    

    It's worth noting that it can be used in combination with metamagic gem too.

    Layout:

    #app/views/layouts/application.html.erb
    <%= default_meta_tags && metamagic %>
    <%= yield %>
    

    And helper:

    #app/helpers/application_helper.rb
    module ApplicationHelper
    
      def default_meta_tags
        meta title: @meta_title || "Default meta-title of my website"
      end
    end
    

    Hope this helps someone out there !