zoonman
zoonman

Reputation: 1163

How to set title in controller?

View application.html.erb contains following content

<title><%= content_for?(:title) ? yield(:title) : t(:stocktaking_title) %></title>

How can I pass data to this view from the controller's method? I mean use symbol :title. I'm don't know Ruby well.

class WelcomeController < ApplicationController
  def download
    view_context.content_for(:title, "My Awesome Title") # doesn't work :( 
  end
end

Rails 4.1.9, ruby 2.0.0 (2014-05-08) [universal.x86_64-darwin14]

Upvotes: 2

Views: 722

Answers (1)

sjagr
sjagr

Reputation: 16502

The prependeded @ character to a variable is what exposes the variable to the view scope. In your controller:

def show
  @title = "My Title"
end

Will let any rendered template file access it using:

<%= @title %>

Clearly, you're looking for some sort of title processing logic. Perhaps you could try replacing the code in your application.html.erb file with something like:

<% if @title %>
    <title><%= @title %></title>
<% elsif content_for?(:title) %>
   <title><%= yield(:title) %></title>
<% else %>
   <title><%= t(:stocktaking_title) %></title>
<% end %>

You could condense this into a ternary but the view wouldn't be very readable.

If you insist on using content_for inside of the controller, you can use the view_context method, but you can't seem to work with content_for directly like so:

view_context.content_for(:title, "My Awesome Title")

Instead, you'll need to implement your own content_for method to extend off of the view_context. I pulled it from this Gist, but here's the code:

class ApplicationController < ActionController::Base
  ...
  # FORCE to implement content_for in controller
  def view_context
    super.tap do |view|
      (@_content_for || {}).each do |name,content|
        view.content_for name, content
      end
    end
  end
  def content_for(name, content) # no blocks allowed yet
    @_content_for ||= {}
    if @_content_for[name].respond_to?(:<<)
      @_content_for[name] << content
    else
      @_content_for[name] = content
    end
  end
  def content_for?(name)
    @_content_for[name].present?
  end
end

This has been tested and works.

Then just do content_for :title, "My Awesome Title" in your controller.

Seriously though, using @title will be way way easier and less "hacky." You could even do something cool like this:

<title><%= @title || content_for(:title) || t(:stocktaking_title) %></title>

Upvotes: 2

Related Questions