10

I have a simple yield use case and for some unknown reason the default case is never shown:

In my super_admin layout I have:

<%= yield :body_id || 'super_admin_main' %>

My controller

class Superadmin::GolfsController < ApplicationController
  layout "super_admin"

  def show 

  end
end

My show view

With or without

<% content_for(:body_id) do %>sadmin_golfs<% end %>

With: sadmin_golfs is shown.

without: empty string is shown instead of super_admin_main

Can anyone reproduce the same behavior ?

mu is too short
  • 426,620
  • 70
  • 833
  • 800
coulix
  • 3,328
  • 6
  • 55
  • 81

7 Answers7

27

Try <%= yield(:title).presence || 'My Default Title' %>

Object#presence is equivalent to object.present? ? object : nil (AS 3 rc docs), and essentially allows the traditional syntax with the titles.

Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338
DirectXMan12
  • 673
  • 6
  • 7
19

Use parentheses:

<%= (yield :body_id) || 'super_admin_main' %>

Or

<%= yield(:body_id) || 'super_admin_main' %>

Without them it is assuming yield (:body_id || 'super_admin_main')

EDIT: Rails 3 uses ActiveSupport::SafeBuffer instead of string/nil (Rails 2), so the output is not nil even if there is no content_for provided. So try:

<%= yield(:body_id).empty? ? 'super_admin_main' : yield(:body_id)%>
Tatjana N.
  • 6,215
  • 32
  • 29
3

Why no test if there are a content_for or not define in view compilation.

In the content_for code we can see :

def content_for(name, content = nil, &block)
  ivar = "@content_for_#{name}"
  content = capture(&block) if block_given?
  instance_variable_set(ivar, "#{instance_variable_get(ivar)}#{content}".html_safe)
  nil
end

So in your case, the @content_for_body_id is define if a content_for is in your view.

You can made :

<%=  instance_variable_defined?('@content_for_body_id') ? yield(:body_id) : 'super_admin_main' %>

If you prefere you can generate an helper after

def yield_or(part, result)
  instance_variable_defined?("@content_for_#{part}") ? instance_variable_get("@content_for_#{part}") : result
end

and call it in your view by

<%= yield_or(:body_id, 'super_admin_main') %>

It's works only with Rails 2.3.x

In Rails 3 :

there are this method content_for?

shingara
  • 46,608
  • 11
  • 99
  • 105
1

In rails 3

raises undefined method `present'

coulix
  • 3,328
  • 6
  • 55
  • 81
1

I know this is an old question but I have a solution for Rails 2.3.

I've extended shingara's yield_or helper method above so it can now accept a block:

module ApplicationHelper
  def yield_or(name, content = nil, &block)
    ivar = "@content_for_#{name}"

    if instance_variable_defined?(ivar)
      content = instance_variable_get(ivar)
    else
      content = block_given? ? capture(&block) : content
    end

    block_given? ? concat(content) : content
  end
end

and this can be used in your templates:

<% yield_or :something do %>
    <p>something else</p>
<% end %>

or

<%= yield_or :something, 'something else' %>
Community
  • 1
  • 1
tristanm
  • 3,337
  • 2
  • 27
  • 40
0
<div class= <%= (yield :content_with_bunners).present? ? yield(:content_with_bunners) : "col-md-10"%>>
stopanko
  • 306
  • 3
  • 7
0

You can use content_for?(:body_id), the code will be like.

<%= content_for?(:body_id) ? yield(:body_id) : 'super_admin_main' %>
brunodles
  • 913
  • 8
  • 9