Ruby on Rails: Yielding Specific Views in a Specific Places in the Layout

Ruby on rails: Yielding specific views in a specific places in the layout

Look into ActionView::Helpers::CaptureHelper. You can do something like this in your views:

<% content_for :sidebar do %>
<!-- sidebar content specific to this page -->
<% end %>

This will run the template inside the content_for block, but will not output as part of the regular template yield buffer, it will be stored in a separate buffer for later. Then later on, including in the layout, you can use yield :content_name to output the content:

<div class="content">
<%= yield %>
</div>

<div class="sidebar">
<%= yield :sidebar %>
</div>

So in a sense you can have different yields for different views, you just have to give the differing content a name with content_for in the views, and yield it with that same name in the layout.

Consider your case, where you want different views in different places. Let's say you have three panels, panel1, panel2, and panel3. You can do this in your layout:

<div id="panel1"><%= yield :panel1 %></div>
<div id="panel2"><%= yield :panel2 %></div>
<div id="panel3"><%= yield :panel3 %></div>

You don't even need to include a plain <%= yield %> if you don't want to. Then in your views, you can choose which panel to display the content in by surrounding the entire view with the appropriate content_for. For example, one of your views might be changed like this:

<% content_for :panel2 do %>
<!-- Your View -->
<% end %>

To show in panel 2. Another one might be intended for panel 3, like this:

<% content_for :panel3 do %>
<!-- Your View -->
<% end %>

Rails: Using Yield, Calling Multiple View Pages

You should, as @cdesrosiers said, rename the index.html.erb file in good_posts to _index.html.erb. Then you can render this view in your application like this:

<div class='span10'>
<%= render 'good_posts/index' %>
<%= yield :good_post %>
</div>
<div class='span10'>
<%= yield %>
</div>

Personally, I would change the index.html.erb file in good_posts folder to _good_posts.html.erb file in app/views/posts folder. Your code will have better meaning, and you can know where to find it after, because it relates to posts. So, if you change this, use this code:

<div class='span10'>
<%= render 'posts/good_posts' %=
<%= yield :good_post %>
</div>
<div class='span10'>
<%= yield %>
</div>

Another you should change is content_for :good_post -> content_for :good_posts , because good posts maybe have many posts, so you should use post in pluralize.

How does the yield magic work in ActionView?

This little tiny method called execute in ActionView::Base explains it all.
http://google.com/codesearch/p?hl=en#m8Vht-lU3vE/vendor/rails/actionpack/lib/action_view/base.rb&q=capture_helper.rb&d=5&l=337

  def execute(template)
send(template.method, template.locals) do |*names|
instance_variable_get "@content_for_#{names.first || 'layout'}"
end
end

The do |*names|... end block is the one receiving the yield. You'll notice that the @content_for_#{names.first} matches up with the variable being set in the content_for process.

It's called from AV::TemplateHandlers::Compilable in #render, and I would assume other places as well.

  def render(template)
@view.send :execute, template
end

http://google.com/codesearch/p?hl=en#m8Vht-lU3vE/vendor/rails/actionpack/lib/action_view/template_handlers/compilable.rb&q=execute&exact_package=git://github.com/payalgupta/todo-list.git&sa=N&cd=17&ct=rc&l=28

how do I link a layout to a view page on Ruby on Rails

There are many ways layout can be used. If you want to call a specific layout for a given action, you should do that in your controller, not in your view. If you need to call in a view, to give a layout for a partial, then the syntax is different, you call the partial first and then the layout.

<%= render partial: "comments", layout: "two_column_landing" %>

If you just want your 2 column view to render in a particular controller then at the top of the controller before any method definitions call, under the class name

class ArticlesController < ApplicationController
layout "two_column_landing"
end

If you want to only call this layout for a specific action in the controller you can do it in the method render

def index
@people = Person.all
render layout: "multi-column"
end

You may refer to this question here for more details.

If you want to remove layout from all action in a controller, add layout false after the class name.

class ArticlesController < ApplicationController
layout false
end

or if you can also specify for each action

def login
...
render layout: false
end

Link to documentation

Using multiple yields to insert content

So, when you go to the index page you will get the piece of html that will be placed in the main layout, and this piece of html look like this:

<div class="container">
<%= render 'admins/menu' %>
<%= yield :admin %>
</div>

This code will yield :admin properly.

When you go to the test page you do not have this html code anymore (since it only belongs to the index method). So, anything you put in the content_for(:admin) block will be ignored since no-one is printing it.

What you probably want to do is creating a shared layout for all your admin pages. Follow this guide and you'll have your solution.

Solution

Edit the application.html.erb layout using this:

<%= content_for?(:content) ? yield(:content) : yield %>

instead of

<%= yield %>

Then create an admins.html.erb file inside the layouts folder to handle your admin pages' layout. Something like this:

<% content_for :content do %>
  <div class="container">
<%= render 'admins/menu' %>
<%= yield %>
</div>
<% end %>
<%= render template: "layouts/application" %>

Will do fine. Then in the index.html.erb and test.html.erb just place regular HTML content, without using the content_for(:admin) block. Everything should work fine and you'll have your custom admin template, with a slightly different look from regular pages.

Possible to create a wrapping partial?

The information is kind of hard to find, but this is covered in the "Rendering partials with layouts" section of the partials documentation. Basically when you do render partial: ... you can use the layout: option to give the name of the "wrapper" layout. The partial will be rendered within the wrapper wherever you put <%= yield %>.



Related Topics



Leave a reply



Submit