Rails check if yield :area is defined in content_for
Asked Answered
A

7

106

I want to do a conditional rendering at the layout level based on the actual template has defined content_for(:an__area), any idea how to get this done?

Archive answered 11/10, 2008 at 8:9 Comment(1)
See my answer for creating a helper method to encapsulate this behaviour in Rails 3.Delibes
I
233

@content_for_whatever is deprecated. Use content_for? instead, like this:

<% if content_for?(:whatever) %>
  <div><%= yield(:whatever) %></div>
<% end %>
Ikeikebana answered 11/3, 2010 at 22:5 Comment(1)
Helper content_for? exists only in Rails 3. In Rails 2 you could use @content_for_... instance variable.Herculean
W
10

not really necessary to create a helper method:

<% if @content_for_sidebar %>
  <div id="sidebar">
    <%= yield :sidebar %>
  </div>
<% end %>

then of course in your view:

<% content_for :sidebar do %>
  ...
<% end %>

I use this all the time to conditionally go between a one column and two column layout

Weeds answered 11/3, 2009 at 20:36 Comment(0)
M
3
<%if content_for?(:content)%>
  <%= yield(:content) %>
<%end%>
Montage answered 18/2, 2014 at 16:49 Comment(0)
F
2

Can create a helper:

def content_defined?(var)
  content_var_name="@content_for_#{var}"    
  !instance_variable_get(content_var_name).nil?
end

And use this in your layout:

<% if content_defined?(:an__area) %>
  <h1>An area is defined: <%= yield :an__area %></h1>
<% end %>
Fong answered 11/3, 2009 at 20:28 Comment(2)
This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post.Neanderthal
I agree @eirikir, not sure what my 6 year younger self was thinking. I'm extending & leaving my answer in for those still on Rails 2.. without the unnecessary preamble ;)Fong
A
1

Ok I am going to shamelessly do a self reply as no one has answered and I have already found the answer :) Define this as a helper method either in application_helper.rb or anywhere you found convenient.

  def content_defined?(symbol)
    content_var_name="@content_for_" + 
      if symbol.kind_of? Symbol 
        symbol.to_s
      elsif symbol.kind_of? String
        symbol
      else
        raise "Parameter symbol must be string or symbol"
      end

    !instance_variable_get(content_var_name).nil?

  end
Archive answered 11/10, 2008 at 16:1 Comment(1)
Heh well I like your self-reply but... Minor point, instance_variable_defined?(content_var_name) is a bit neater than instead of testing whether it is nil. Second bigger point, the content_for instance variable is deprecated so your solution is not future proofPhospholipide
P
1

I'm not sure of the performance implications of calling yield twice, but this will do regardless of the internal implementation of yield (@content_for_xyz is deprecated) and without any extra code or helper methods:

<% if yield :sidebar %>
  <div id="sidebar">
    <%= yield :sidebar %>
  </div>
<% end %>
Phew answered 16/11, 2009 at 12:1 Comment(0)
R
0

I use @view_flow and value of the content method before checking if the content is present in the view like this:

@view_flow.content[:header_left_or_whatever_the_name_of_your_block_is].present?

Recently stumbled upon it when showing all local, global and instance variables of self in the console with byebug. I’m a fan using this because it’s straight from Rails, won’t throw an error, won’t hide anything w “Rails magic”, returns a definite true or false, + only checks the content in the current context of the view being rendered.

@view_flow is an instance attribute of ActionView::Context and because Action View contexts are supplied to Action Controller to render a template it will be available to any view that has been rendered by Rails. Although it checks for content, the content_for block will not be yielded if it isn’t there. So it’s been my perfect solution in similar situations.

Raul answered 8/7, 2022 at 3:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.