How can I use the same layout multiple times on a page? - ruby-on-rails

TL; DR: How can I use the same layout multiple times on a page? All attempts to render partials with recurring layouts go into the elements where the first time the layout is used.
Quick Info:
Using
Rails 2.3.14
Ruby 1.8.7
My partials use content_for, which is pretty handy with layouts.
Basically, my layout looks like this:
<div class="header">
<%= yield :modal_header %>
</div>
<div class="body">
<%= yield :modal_body or yield %>
</div>
Generally, this is how I use my modal layout:
<% content_for :modal_header do %>
header text / elements
<% end %>
<% content_for :modal_body do %>
body info / settings for object or warning message, etc
<% end %>
This is how I render modals on my page:
<%= render :partial => "section_options", :layout => "modal" %>
and that works really well
BUT
when, on the same page, I try to render another modal:
<%= render :partial => "section_content_options", :layout => "modal" %>
This is what happens to the modal at the top of my page (occurs first in the HTML document)
<div class="header">
-- header from second partial --
-- header from first partial --
</div>
<div class="body">
-- body from second partial --
-- body from first partial --
</div>
and then later in the page, where the content from the second partial is supposed to be:
everything is rendered correctly ...
For the sake of this example:
<div class="header">
section content options
</div>
<div class="body">
section contents options ... options
lil confirm / cancel buttons
</div>
Is there a way to fix this? This behavior really messes with javascript bindings as well. so. yup.
Is there a bug with layouts in rails 2.3.14? do I have to upgrade to rails 3 to get rid of this problem?

Modals should be rendered using partials, not layouts. Layouts are designed as a way of defining the overall layout of the entire site, not specific parts. Something like a modal (which by design is specific) should be a partial that's rendered either through a condition or JavaScript.

Related

I want my carousel to be appeared in index page only in rails application

I am new to rails and I want my carousel code to be seen in the index page only,please give a solution and below is my code :
<body>
<%= render 'layouts/navigation'%>
<%= render 'layouts/carousel' %>
<%= render 'layouts/messages'%>
<div class="container">
<div class="row">
<%= yield %>
<div class="col-md-8">
</div>
<div class="col-md-4">
</div>
</body>
Normally you'd want the move any code that's specific to a page out of the layout and into the template for the appropriate action.
However, in your case that piece of code looks embedded within the rest of the page skeleton so it could be hard to refactor it that way.
For this reason I'd suggest using conditional rendering by simply using a Boolean variable.
For example you could do:
<%= render 'layouts/carousel' if #render_carousel %>
And then you could just set the #render_carousel variable to true for any action that you'd want the carousel to appear in, e.g.:
def index
# rest of the code
#render_carousel = true
end

DRY view for sidebar

In my quest to keep my application views as DRY as possible I've encountered a little snag. My appliation.html.erb incorporates a static sidebar menu. Each of my main controllers incorporates a secondary sidebar menu (essentially a submenu). I can take the code that renders the menu out of application.html.erb and put it in each of my views and change the secondary sidebar there, but this produces a lot repetition in my views.
I saw this SO post and looked at this page, but I was unable to get either idea to work. I was thinking that I could put something like:
<% provide(:submenu, 'layouts/sidebars/sidebar_customers_contacts') %>
at the top of each view and use that to render the associated partial by doing
<% content_for(:submenu) do %>
<%= render :partial => :submenu %>
<% end %>
from the application.html.erb but of course that didn't work.
This is my current application.html.erb:
<div class="side">
<%= render 'layouts/sidebar' %>
<%= render 'layouts/sidebars/sidebar_dashboard' %><!-- this needs to load a sidebar based on the controller that calls it. Each view of the controller will get the same sidebar. -->
</div>
<div class="main-content">
<%= yield %>
</div>
I feel like I'm making this more difficult than it really is. Is there a simple way to do this?
Rails provides a helper called controller_name which you can read more about here.
Assuming you adhere to your own naming conventions, this should work as-is. If you decide some controllers don't get a sidebar, you may need to throw in some conditionals...
application.html.erb
<div class="side">
<%= render "layouts/sidebar" %>
<%= render "layouts/sidebars/#{ controller_name }" %>
</div>
<div class="main-content">
<%= yield %>
</div>
EDIT
Sorry, my mistake was using single quotes instead of double-quotes. You cannot use #{string interpolation} within single quotes. Source

Application.html.erb template inheritance

I have a situation in rails (version 4.04, ruby version 2.1) where I've been using the standard application.html.erb to define the main framework for my site, header, footer, nav bar, etc. When I got to an inner div, call it, inner-content, thats where I put a <% yield %> statement so that the sub template can take over and place its content in the correct place (for example products#show or products#index have show.html.erb and index.html.erb respectively which just the content for those actions).
The problem is I realized I was duplicated some code in those sub templates. In ever one of them (except one) I always was starting off like this:
<div class="columns large-6 medium-6 center-small">
<div class="inner_wrapper">
And I was always ending like this:
</div>
</div>
So I was thinking, I shouldn't be repeating all this code. I should move this into application.html.erb so that every template automatically gets the inner-content set up correctly.
The problem is that one action I was talking about. There is one action that has a different setup. I don't want to have to type in those extra 2 divs for every sub-layout except one. Is there a better way to do this?
One way could be to check which controller your currently using this in your application.html.erb
<% if params[:controller] == "controller name" %>
<div>
<%= yield %>
</div>
<% else %>
<div class="different div">
<%= yield %>
</div>
<% end %>
Not sure if this the best way, but its one way to do it.
Create a different layout file and call it maybe products_layout.html.erb.
Then in the controller
class ProductsController < ApplicationController
layout: 'products_layout'
....
end
Or do it on a per action
def show
render 'show', layout: 'products_layout'
end
http://guides.rubyonrails.org/layouts_and_rendering.html

How would I go about adding a simple menu to a Rails Application? (How to use yield :menu)

I want to add a menu to my First Ever Rails Application. Nothing too complicated.
I've worked out that I should maybe reference it from application.html.erb, but after that I'm stuck.
Here's what I've got so far (It's not much)
<%= render :partial => "menu" %>
If I'm rendering a partial call "menu" in application.html.erb, where do I put the menu file, and what do I call it? Does it need to go in the controller of the view?
Can I call this partial from whichever layout subfolder I'm in?
Part II. If I want to show different content according to the view I'm in - how do I do this?
<body>
<p>[<%= yield :menu %>]</p>
<%= yield %>
</body>
</html>
I'm just learning Rails, so sorry about the stupid questions. Also, I'm interested in not only a solution, but also an idea of best practices.
In basic terms you are looking for the content_for helper. You put this inside your views which will then populate named blocks in partials or layouts such as :menu. You may elect, if you wish, to use partials to actually define the content for the content_for regions.
In a view:
<% content_for :menu do %>
<ul>
<li> ... </li>
<li> ... </li>
</ul>
<% end %>
or as:
<% content_for :menu do %>
<%= render :partial => "some_menu_content" %>
<% end %>
In the layout or partial:
<div id="menu">
<%= yield :menu%>
</div>
Watch this screencast from the Railscasts series for more information. It's old but still applicable

Creating content for rails-based applications

I'm facing a problem of cleaning up my application in Ruby on Rails. What I have is a pretty standard 3-panel, header and footer layout where different parts of the screen contain different functionality.
By that I mean for example that the header contains (among others) a select that allows one to select parts of the application and a context-dependent menu. The main content area contains obviously the most interactive stuff whereas side panels contain quick-links with stuff like shopping-cart preview, list of potentially attractive products for the customer, a selector to narrow down the list of options...
I was wondering how do I go about simplifying the design. Right now I have the stuff that provides data for the "common" stuff (as opposed to direct content that's placed in the center) called from all the actions (with a filter) but that doesn't feel right for me. I've read that "components" are also not the way to go for obvious performance reasons.
Is there something that's more like component-oriented (other frameworks do have that kind of stuff - Grails: <ui:include ../>, ASP.NET MVC: <% Html.RenderAction() %>)?
Best regards, Matthias.
You can use content_for for managing different location of a layout.
layout.html.erb
<body>
<div id="header">
</div>
<div id="content">
<div id="main">
<%= yield %>
</div>
<div id="side_bar">
<%= yield :side_bar %>
</div>
</div>
<div id="footer">
</div>
</body>
In your views use content_for to assign content to various sections of the layout:
<% content_for :side_bar do %>
<div>
<h1> Popular Posts </h1>
</div>
<% end %>
<div>
<h1> All Posts </h1>
<% #posts.each do |post| %>
<h2> <%= post.name %> </h2>
<% end %>
</div>
Reference:
Railscast
Edit 1
You can use partials to create reusable screen sections.
views/shared/_shopping_cart.html.erb
<div>
display the shopping cart details
<div>
views/posts/index.html.erb
<% content_for :side_bar do %>
<%= render :partial => 'shared/shopping_cart' %>
<% end %>
Essentially you can use:
Filters to set data
content_for to set layout
partials to display data
Combination of these three should allow you to componentize your solution.
layout
In app/views/layouts, a global layout application.html.erb defines the outer most layout (e.g. your 3-panel design).
The application layout can be overrided by a controller layout. For example, if you have a Tasks controller, you can add a tasks.html.erb in the app/views/layouts folder. The tasks.html.erb will be your default layout for any Tasks views (index, add, edit, etc.)
In application.html.erb or tasks.html.erb, you may add two partials, e.g. _header.html.erb, _side.html.erb. Those two partial will serve as the default panels for the views.
A better tutorial is at http://guides.rubyonrails.org/layouts_and_rendering.html

Resources