Template, Partials, and Layouts in Rails? - ruby-on-rails

Reviewing some starter courses, I see that the terms are used separately, but I think I only understand layout. To my knowledge the layout is a temporary portion of code (such as a right navigation section, a div containing an ad, or something similar), and a partial is a partial template, but what is a template, and how does it differ from a layout?
Can you give a definition of all three with relations to each other if possible? (ie a template is .... and there are two kinds, partials and layouts.... layouts are specific types of templates or whatever the answer is)
Please correct my assumption if needed...
In Railscasts 294 using pjax, layouts are explicitly differentiated by the random number generator, and this is why I got lost.
I am trying to make a single page accessed by App/Verb/noun, where i can either "capture" or "display" "photos", "videos", "images", etc...(app/captures/photos or app/captures/videos or app/displays/photos etc) and am trying to make just one div change based on when I "capture" different things.... and I am getting lost in the verbiage, or I get really close but am not really understanding what im doing.

I know this is an old question, but I've wondered the same. In the guides, there is no clear explanation of the difference between layouts and views, nor is there a clear explanation of the relationships. To add to the confusion, the term 'template' is often used for both. As someone that was programming Smalltalk in the 90s (but is new to Rails) I deeply understand MVC and understand some of the many ways that it an be implemented -- so my confusion wasn't with that part. There's just a missing piece of context about views, layouts, and templates and how they relate to each other.
Here's how I came to understand it:
Start with a simplistic understanding and example so that the relationship and role of each part is clear:
a view is 'stuff to be displayed' for a particular controller to respond to an action (which puts it into a particular state). A view is a snapshot of your model at in a particular state, for a particular action (reason/context). It's about information and state, not necessarily about 'looking good'.
a layout has specific information on how something will be displayed. It may have markup (CSS, HTML, etc.) that provides instructions on how something will be organized (this part up here, that part over there, those go at the bottom, these float at the top; that is navigation information, this is H1, that's H3, this is a definition..) and how it will look (left, right, up, down, red, green, emphasized, flashing, hidden, big, tiny, Helvetica, etc.)
Think "Layout and Looking Good"
Say you have a Contract model and controller, and you have a file that defines the view: view/contracts/show.htm.erb:
<% content_for :full_identification do %>
<p><%= contract.display_name %> <%=contract.full_id_number %> </p>
<% end %>
<% content_for :summary do %>
<p> This is the summary for <%= contract.simple_name %>. You hire us. We give you coolness. You pay us.</p>
<% end %>
<% content_for :client_info do %>
<div class="client-info">
<p><span class="contract-title">Client: <%= contract.client_name%></span></p>
<p>Address: <%= contract.client_address%></p>
<p>Phone: <%= contract.client_phone %> </p>
... more info about the client....
</div>
<% end %>
<% content_for :scope_of_work_statement do %>
<p class="scope-of-work-statement"><%= contract.scope_of_work%>:</p>
<% end %>
Your layout file would have more details about the HTML (assuming HTML output) and specifics about how you want things to look. Maybe you have a controller and view that is specific for what (and how) the client sees that contract. You have a layout file for that specific controller and it looks like this:
layouts/contracts/contracts_clients_view.htm.erb
<div class="tab-pane fade in" >
<div class="span7 highlight >
<%= yield :full_identification %>
<div class="no-breaks reflow" >
<%= yield :summary%>
</div>
</div>
<div class="span5 scope-of-work-statement">
<h3>Scope of Work Statement</h3>
<%= yield :scope_of_work_statement %>
</div>
</div>
</div>
*[This is a totally contrived example so that I can make the relationship between view and layout clear. Obviously things would be modeled and expressed differently in the real world. ]*
The view provides input (the content pieces) to the layout.
Views are for controller actions and are named accordingly. (Ex: show, edit, index, etc.)
Layouts are named for the controller used to render them. (Ex: application -- for the ApplicationController, contract -- for a ContractController, contract_customers_view -- for a ContractCustomersViewController)
Where it starts to get tangled is that a view can also have layout information in it. Sometimes there is only the view file (no layout file). And either one can be written in a template language (like ERb or HAML) and thus they can both referred to as a template.
A partial is really just what it says: it's just a piece that can be used (and hopefully re-used). You can take part of a view or layout and re-factor it so that you can re-use it -- now it's a partial. Common uses of partials include the head section, navigation sections (including header, footer, etc.), places where you can re-factor for reusability, and improving coding style and readability by using them for semantic and logical sections. (That's why people liken them to a subroutine.)
Another place where you can get some context about views and layouts and how they're different is in the steps (flow) that ActionView goes through to actually produce output -- to render something using all of these pieces. It is important to understand when a layout is (or isn't) created, for example, so you understand which variables and parameters are or aren't available to you at a particular time.
(I'm working with Rails 4, btw.)
Given all of that, now imagine that all of your layout information is in your views, and that your views are written in a template language (ERb, HAML, etc.), and that you've used partials to make everything sing better. You may not have any layout files beyond one main one for your application that has a big yield in it where the real content (generated by your controllers & models) goes.
Hope this helps someone else get a handle on views and layouts. (And I suppose I should suggest putting something like this into the guides.)

From http://www.tutorialspoint.com/ruby-on-rails/rails-layouts.htm : A layout defines the surroundings of an HTML page. It's the place to define common look and feel of your final output. Layout files reside in app/views/layouts.
Template is a general term for the view files. A view template - residing in app/views/ folder - would be rendered within a layout.
Best resource to understanding how Rails views work is the Ruby on Rails Guides page on Layouts and Rendering : http://guides.rubyonrails.org/layouts_and_rendering.html

What is a layout?
(a) Let's start with the problem we are trying to solve
You might have 1000s of different "pages"/views on your rails app. All 1000 of those pages/views share the same headers, and footer. Now imagine you had to change the footer for your site: you would have to make that change in 1000 pages! What a nightmare: this is not efficient.
You can extract the headers and footers and place it in a layout.html.erb file which can be used by all 1000 pages. In that way: 1 change in one place can propagate to all 1000 of your views/pages. So if you want to change your header/footer you only need to make that change in ONE place, and that will be applied to all views that utilise that relevant template.
# example of a layout
# app/views/layouts/application.html.erb
<!DOCTYPE html>
<-- THIS IS SIMPLIFIED - DO NOT COPY this example -->
<html>
<div>
<%= yield %> <-- Notice the yield statement -->
</div>
</html>
# example of a view:
# users#show.html.erb
<-- This uses the application.html.erb layout -->
<-- Notice how I don't have to create a html tag - because this has already been created in the application.html.erb -->
<div class="container">
<h1> About <%= #user.full_name %> </h1>
<br>
<p>
<b> Name: </b> <%= #user.full_name %>
</p>
<p>
<b> Organisation: </b> <%= #organisation.name %>
</p>
<p>
<b> Email: </b> <%= #user.email %>
</p>
</div>
The rails app firstly renders the layout, and then yeilds to the specific views that you want to display. Now you can change the layout and have it propogate through to all your subsequent "views" which utilise the layout.

Related

Ruby on Rails: provide vs content_for

I came across the view helper function "provide" today. By looking into its manual I am still confused on how it is different from "content_for".
provide(name, content = nil, &block)
The same as content_for but when used with streaming flushes straight
back to the layout. In other words, if you want to concatenate several
times to the same buffer when rendering a given template, you should
use content_for, if not, use provide to tell the layout to stop
looking for more contents.
Question 1: this is quite abstract to me - could anyone flesh it out by giving a demonstrative example?
Question 2: working with asset pipeline, which performs better and why?
Thanks!
First of all, what is streaming? Why would you use it?
Streaming is alternate method of rendering pages top-down (outside-in). The default rendering behavior is inside-out. Streaming must be enabled in your controller:
class MyController
def action
render stream: true # Streaming enabled
end
end
According to the documentation:
Streaming may be considered to be overkill for lightweight actions
like new or edit. The real benefit of streaming is on expensive
actions that, for example, do a lot of queries on the database.
So, if you're not using streaming, is there still a difference?
Yes.
The difference is a template can define multiple content blocks by calling content_for multiple times. Doing so will concatenate the blocks and pass that to the layout:
# layout.html.erb
<div class="heading"><%= yield :surprise %></div>
<div class="body">
<p><%= yield %></p>
<p>But it's not very interesting...</p>
</div>
# template.html.erb
<%= content_for :surprise, "Hello" %>
I've got your content!
<%= content_for :surprise, ", World!" %>
# Generated HTML
<div class="heading">Hello, World!</div>
<div class="body">
<p>I've got your content!</p>
<p>But it's not very interesting...</p>
</div>
Since provide doesn't continue searching the provided template, only the block passed to the first provide call will be sent to the template:
# layout.html.erb
<div class="heading"><%= yield :title %></div>
# template.html.erb
<%= provide :title, "Foo" %>
<%= provide :title, "bar" %>
# Generated HTML
<div class="heading">Foo</div>
Was curious to see what the difference was, and as Thong Kuah pointed to the api, inside the answer:
This means that, if you have yield :title in your layout and you want to use streaming, you would have to render the whole template (and eventually trigger all queries) before streaming the title and all assets, which kills the purpose of streaming. For this reason Rails 3.1 introduces a new helper called provide that does the same as content_for but tells the layout to stop searching for other entries and continue rendering.

How to render horizontal page layout with multiple frames

We have a simple app which has a horizontal layout (left hand side panel and content on the right hand side), with a header and footer. So if you click on a certain object on the left hand side, the view is rendered on the right hand side with navigation panel in the header and footer links. The layout actually renders content on the same page itself for any action on the left hand side and the contents of the left hand side will differ based on the section chosen in the header. How should we go about designing the routes in these cases, which differs from the basic navigation where every action is rendered on a different page.
My routes looks like this..
resources :foos do
resources :foo_bars do
end
end
I would need to show all foos on the left hand side panel and if the user selects a foo it needs to show properties of foo and foo_bars in a table on the right hand side panel. How will the view look for me and how will the URL at the browser look for me? We will have several tabs at the top and based on that you will show foos or similar top level objects
The routes remain the same. You would need to ajaxify your calls.
If your question is:
how should we go about designing routes
The way you have it is just fine if you want to utilize nested resources, and in your case it seems logical.
http://guides.rubyonrails.org/routing.html#nested-resources
Currently, your url will be as follows: /foos/:foos_id/foo_bars/some_action
Let me rename these so things make more sense. Lets say foos is categories, and foo_bars is actions.
Personally, I would override the to_param in the categories model file.
to_param
#return a more readable attribute here
name
end
In this way, your URL would be more closely tied with the names of all the categories on the left side of your page.
So now, if you had a record in the categories table which had the name animal, your URL would look like this: /categories/animal/actions/some_action
That seems pretty logical to me. Make sure in your controller you fetch the record via the proper attribute if you use to_param.
I would apply the same principal to the nested resource as well, then your whole URL would be accurately representing what tab is selected on the page. If you had a record in actions with the name "running", and you had things setup properly, then you could have your url look similar to: categories/animal/actions/running.
You could play around with all the options in your routes file, then use rake routes in terminal to see what changes and what your urls will look like before you even touch the browser.
Here are some extra resources for you.
http://apidock.com/rails/ActiveRecord/Integration/to_param
http://guides.rubyonrails.org/action_controller_overview.html
Hope this helps.
There is no good answer to your question - it all significantly depends on the layout of your application. Besides, there are valid answers here about to_param, and using AJAX, that add important details. But, to give you a head start.
For your views/foos, rewrite your index.html.erb as:
<%= render partial: "show_foos", locals: { foos: #foos, selected_foo: nil }%>
And your show.html.erb as:
<%= render partial: "show_foos", locals: { foos: #foos, selected_foo: #foo }%>
In your foos_controller.rb in show method you need to obtain both #foos and #foo, e.g.:
#foos = Foo.all
#foo = Foo.find(params[:id])
Now, to the fun part. Back to views/foos directory. Create a partial called "_show_foos.erb" (the one that we called both from #index and #show). Do something like:
<table>
<tr>
<td>
<%= render partial: "show_foos_list", locals: { foos: foos, selected_foo: selected_foo }%>
</td>
<td>
<%= render partial: "show_foo_props", locals: { selected_foo: selected_foo }%>
</td>
</tr>
</table>
Please note that's an extremely brute & ugly example that creates a table with two columns: one for the list of foos in the left "panel", the other for displaying the results for the selected foos in the right "panel". In real life use divs and styling. Also, consider pushing the layout to where it belongs - to the appropriate layout file - and using named yields there. But, as I said, a headstart - simple table.
Now, just define the two partials mentioned here. First, the "_show_foos_list.erb" that lists the foos on the left. Assuming each foo has a 'title' attribute, something like:
<% foos.each do |foo| %>
<%= link_to_unless selected_foo && (foo.id == selected_foo.id), foo.title, foo %><br />
<% end %>
Second, the foo & foo_bars on the right - "_show_foo_props.erb":
<% if selected_foo %>
# Here display the Foo attributes
<h2> Foo: <%= selected_foo.title %> </h2>
<% selected_foo.foo_bars.each do |foo_bar| %>
# Here display each FooBar that belongs to Foo
<h3>FooBar <%= foo_bar.title %></h3>
<%= foo_bar.description %>
<% end %>
<% end %>
Again, very crude example. Replace 'title', 'description' with the right sets of parameters, use partials to display FooBars. Do the styling with CSS. Etc, etc, ... Refactor as you see fit.
Talking about the routes. What you get is when you go to your "www.yourapp.com/foos" url is the list of all foos on the left, nothing on the right. Once you press on any foo in the left column, you go to "www.yourapp.com/foos/:id", where :id is the ID of the selected foo (and consider to_param from the other answer here or more advanced techniques to make this part meaningful) and get the list of foos on the left, and the properties of the selected foo and all foo_bars belonging to it on the right.
Hope that helps to start laying out your own implementation based on the rough idea presented here.
If I understand your question correctly, the answers saying Ajax is required are not correct. I have an ancient Perl app (written in 1999) that does this. Am currently re-implementing in Rails, and it's working fine. Frames make it particularly easy to allow the data to scroll while the menu stays fixed.
You do need to use HTML4 frames, which are deprecated in HTML5, It's possible to use an IFRAME for the data rendering frame and be HTML5 compliant, but the result is less usable than the FRAME solution in HTML4, at least with some browsers.
As others have said, your routes are fine.
The trick is to use the target field in the form to direct the Submit response to the rendering frame. My haml code for the "command" frame is
= form_tag admin_menu_path, :method => :put, :target => 'data_frame' do
...
The rest is just a normal form. This form remains constant in (my case) the left frame while responses replace each other in the right data_frame.
The matching frame HTML is:
<frameset cols="360,*">
<frame name="menu_frame" src="...">
<frame name="data_frame" src="admin.htm">
</frameset>
You would have to use an outer frameset to get the header and footer, but this should be straightforward.
I am ready for comments saying frames are far from best practice. But for this particular application, they are perfect: simple, understandable, and extremely browser independent. E.g. my 1999 Perl generated code ran fine on IE 2.0 and Netscape (the ancestor of Firefox, friends). And it's still perfect on every modern browser I can find. Wish Ajax could say the same...
If I've misunderstood your question, I'll happily delete this response.

Design pattern for side bar with dynamic content in Rails

I would like to have a right side bar with content changes for each page.
For example, when I am in Friends page, the side bar should display New Friends.
When I am in Account page, the side bar should display Recent Activities.
How should I go about this to respect Rails design patterns? I heard about Cells gem, but I am not sure if I use it.
here is one way, in your layout add a named yield section
<div id="main-content">
<%= yield %>
</div>
<div id="side-content">
<%= yield(:side_bar) %>
</div>
Then in your views put content into the named yield using content_for
# friends view ....
<% content_for(:side_bar) do %>
<%= render :partial => "shared/new_friends" %>
<% end %>
# account view ....
<% content_for(:side_bar) do %>
<%= render :partial => "shared/recent_activity" %>
<% end %>
this requires you to be explicit about what content appears in the side bar for every view,
maybe having it do it dynamically is better? probably depends on the specific situation and your preference
see also - http://guides.rubyonrails.org/layouts_and_rendering.html#understanding-yield
I came by this question in a moment of a big design change in our views. After thinking about the sidebar problem a bit, I realized that there's no best solution (as always). There are better solutions for each case.
I'll compare 3 solutions here:
using content_for(:sidebar) and yield(:sidebar)
using the partials approach
using the Cells gem
1. Using content_for(:sidebar) and yield(:sidebar)
This is good for cases when each link (each controller action) you access renders a different sidebar. In this case, each view you access will have the content_for(:sidebar) part.
If your sidebar view depends only on the state of some variable in the session, for example, the sidebar should not be rendered for every link you access.
Then you should use a good caching system like turbolinks, to avoid rendering many times the same thing, or use something like the Cells gem with a javascript to render only the main part of the layout.
2. Using partials
Using partials is always good to eliminate duplication. If your sidebar is very simple and is changed for every controller, you can render it as a partial. But if you're rendering different partials in the same controller, according to some state, it may be an indication that you have business logic in your views, which should be avoided.
3. Using the Cells gem
Very good design pattern when you have to render your sidebar from a different controller than the rest of the view each time.
It takes a lot of business logic out of the view, which sure is a good practice.
Here you have an action calling a view. Inside that view, there is a statement render_cell(:sidebar, params). This statement will do some business logic and render the view of the sidebar. It's as if the first action called other controller actions to render specific parts of your view (called cells)
If you make changes to the sidebar only, you may have to create other simple action, so that a javascript will request it. This action will call the render_cell(:sidebar) method again to respond with the view.
It's a very interesting approach.
Other ideas:
Your sidebar could be rendered only with javascript from the same
action.
Your sidebar could be rendered by an angular controller, and rails sends jsons with the sidebar objects. (look for "One page apps")
try something like this
<div class="sidebar">
<% if current_page?(controller => "friends", :action => "show") %>
<h4>New Friends</h4>
<% elseif current_page?(controller => "accounts", :action => "show") %>
<h4>Recent Activities</h4>
<% end %>
</div>
If the above code fits what you are trying to do(looks like this is what you want to achieve), then stick with it, else it may be beneficial to go with some gems. Also checkout helper page on how to use current_page? method. Hope it helps

Few questions about jqtouch

I am using Rails 3. Consider the following code listed at bottom.
1) Should links to other actions be done via href (href="/foo/bar") or via #id (id="#foobar_div")? In some document I read online. Providing an actual link to the href attribute tells the iPhone to execute an AJAX call.
If I provide an div#id instead, then it loads the page without ajax (the same way browsers do this). However, providing div#id's means that all content has to be declared a single page.
Whats the right way for calling other pages on the server?
2) Is there anything wrong with the code structure below? i.e. can I style my own span elements like this?
3) The demo pages indicate that all content should be in one page. However, Ryan Bates from railscast.com has an episode about jqtouch and his pages are separate. which is the proper way?
<ul>
<% #songs.each do |song| %>
<li class="arrow">
<%= link_to(song_path(song)) do %>
<%= image_tag(song.user.profile_image, :alt => 'profile image', :style => 'float:left;') %>
<span class="title"><%= song.title %></span>
<span class="artist">by <%= song.user.first_name %></span>
<span class="likes"><%= song.likes.count %> loves</span>
<% end %>
</li>
<% end %>
</ul>
For your first and third questions (which to me are the asking the same thing), it depends on the project you're working on.
If you're providing static contents, you can just load all the pages in one hit, hence using "id=#foobar_div", as long as there are not that many pages (as you don't want the users to hold the phone and look stupid in front of their friends waiting 30 minutes for your site to load).
If you're providing dynamic contents or there are too many pages for your site, you may want to use the AJAX approach, at least for some pages.
At the bottom line, you want to load as many static pages as possible while still keeping your site responsive.
For question 2, I'm not quite sure I got what you're asking. I can't see anything obviously wrong, but again, I'm not a rail programmer.

How can I use content_for to put something in :yield

I am in ruby 1.9.2, rails3.
So My website has some structures,
and I want to put menu in a middle of my webpage.
I am doing something like (within application.html.erb file)
blahblahblah
<div id="menu">
<%= yield :menu %>
<div>
blahblhablah
I have a file menu.html.erb which has menu structure for the site.
What can I do if I want to use a file within ./layout folder to be used to be part of that yield :menu? I was wondering, if I have to use content_for for every controller, and within every functions...
Btw, menu.html.erb will be different for each controller, so thats why I am yielding it.
In conclusion, I just want to include one common shared menu.html.erb pretty much everywhere.
You could do something like this in your views:
<% content_for(:menu) do %>
<%= render :partial => "/layouts/user_menu.html.erb" %>
<% end %>
You could try to combine this with controller.controller_name (not sure this works for Rails3) and load a different menu for each controller automatically.
You might consider watching the railscast on layouts, it's concise and helpful.
Numbers 7 and 8.
http://railscasts.com/episodes?search=layout

Resources