Rails 3 nested layouts: how to add at the end? - ruby-on-rails

Is it possible to manipulate the placeholders so that I can not only set their content, but also add/remove content in a particular order? For example:
layouts/base.html.erb (a base layout meant to be extended):
<!DOCTYPE html>
<html>
<head>
<title><%= yield :title %></title>
<%= yield :stylesheets %>
<%= yield :javascripts %>
<%= yield :csrf %>
</head>
<body>
<div class='container-fluid'>
<%= yield :header %>
<%= content_for?(:content) ? yield(:content) : yield %>
<%= yield :footer %>
</div>
</body>
</html>
layouts/application.html.erb (this is the layout I will be using for the most part of my app, it inherits from the base layout):
<% content_for :stylesheets do %>
<%= stylesheet_link_tag "application", :media => "all" %>
<% end %>
<% content_for :javascripts do %>
<%= javascript_include_tag "application" %>
<% end %>
<% content_for :csrf do %>
<%= csrf_meta_tags %>
<% end %>
<%= render :template => 'layouts/base' %>
Now I want a layout for a specific controller, which may need to add more javascript links, or maybe completely remove them. Let's say I want to add only one file after the other javascripts. So far I got this:
layouts/some_controller.html.erb (this is a layout for a particular controller, it should inherit from the application layout):
<% content_for :javascripts do %>
<script src="/assets/some_javascript_that_depends_on_jquery.js" type="text/javascript"></script>
<% end %>
<%= render :template => 'layouts/application' %>
This won't work, because it will place some_javascript_that_depends_on_jquery.js at the beginning of the :javascripts placeholder, and I need it at the end because it depends on jquery.
It would suck to have to extend the base layout directly, and keep track of any change made to the application layout to apply it to the controller-specific layout too.
What would be the recommended way to deal with this situation?

In application.html.erb, Keep the contents of content_for :javascripts in a partial
Here your partial will have
<%= javascript_include_tag "application" %>
Then, call the same partial in addition with other javascripts in other layout.
Another way,
You can call one helper which will have a hash like this:
js_files = {"application_controller" => ["js_file_1"], "some_controller" => ["js_file_1","js_file_2"]}
Now, fetch the js files and construct the javascript include tag in run time based on controller in your content for.
Hope this will be more flexible.
Sorry for not formatting.

Always keep one js file per controller.
<%= javascript_include_tag params[:controller] %>
lets take example of users controller then there will be users.js.coffee file.
If you want to have multiple js files for users controller then you can require those files inside users.js.coffee file
vi users.js.coffee
//= require 'a'
//= require 'b'
/* my extra js code will go here */

This can't be done as in other frameworks where you just extend layouts and then modify the inherited blocks at will.
Rails sort of forces you to keep it simple.

Related

content_for are not rendering in partial views

I have a rails app which uses a layout
The simplified version looks like this:
<html>
<head>
<%= render 'layouts/head' # renders the "layouts/_head.html.erb" partial correctly
# the most head (css/js) content gets implemented here %>
</head>
<body>
<%= yield # renders the current action %>
<!-- implement alls scripts which should be exectued on the bottom of the page -->
<%= content_for :scripts_bottom %>
</body>
</html>
in my `layouts/_head.html.erb' I use
<%= content_for :scripts_head %>
<!-- it seems `content_for` instead of `yield` appends content -->
In my partials I place the following snippets to append them :scripts_head. (some of my partials should put javaScripts
<% content_for :scripts_head do %>
<%= javascript_include_tag 'some_script' %>
<% end %>
The content_for in the `layouts/head' renders nothing
How can I resolve that?
It looks like that partials are not able to append their content_for content when the content_for :blah do is placed BEHIND the echoing content_for / yield tag.
If I try try content_for :scripts_bottom it will get rendered at the bottom of the page.
Thanks in advance
Rails 3.2.14
ruby 2.0.0p247
instead of provide, try <%= content_for :scripts_head %>
If you want to use content_for then you need to yield it in your head instead of render.
So your header would look like:
<%= yield :scripts_head %>
Alternatively you can remove the content_for in your partial and just have the JS by itself like this:
<%= javascript_include_tag 'some_script' %>
Then you wouldn't have to change your layout file.
In your layouts/head partial, use yield :scripts_head not content_for

Yield layout in rails

I'm trying to add a layout to the application layout. I having trouble trying to figure out all the different layout solutions. First I tried just a layout inside a layout because I didn't fully grasp what partials are or if they are layouts also? Maybe I can start with that question. What is the difference between a layout and a partial.
Here is what I have right now. I'm trying to just separate out my header code which has a navigation and some other elements into a separate layout. I want this layout to be on all views. Meaning it should be a layout inside the applications layout along with other views that are been called when their controllers are called. Which is covered in my code with the <%= yield %>. That yeild works but the :header one does not.
Application Layout app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>home</title>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<div id="header"><%= yield(:header) %></div>
<%= yield %>
</body>
</html>
Header layout app/views/layouts/application.html.erb
<% content_for :header %>
<p>HEADER TEXT</p>
<% end %>
Why would the code above not work?
I also saw code like this that I tried but it gave me an error.
<%= render layouts/header %>
Can someone please explain all these different methods.
Thanks.
It's good practice to separate your header and footer into partials which you would live in the views/layouts folder as '_header.html.erb' and '_footer.html.erb' respectively.
You can then optionally wrap each partial with specific div's which is what you're trying to do with the header (you could do the same with the body too), and it would end up looking like this:
<!DOCTYPE html>
<html>
<head>
<title>home</title>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<div id="header">
<%= render 'layouts/header' %>
</div>
<%= yield %>
<div id="footer">
<%= render 'layouts/footer' %>
</div>
</body>
</html>
That will do what you want it to do.
Note that 'layouts/header' and 'layouts/footer' have '' around them.
To answer your question on what is the difference between a layout and a partial, well a layout is something that will used throughout your application, such as a consistent header or footer. A partial can be a layout, but it doesn't have to be, so you can partial specific to other views across your site.
<% content_for :header do %>
<p>HEADER TEXT</p>
<% end %>
You forgot the do
So - first - The yield syntax may or may not be correct, but I've never seen it, and I don't like it. I only ever call yield once in a file.
If you want to render a header in your application template file, that's certainly possible - my advice would be to place it in your template file directly - after all, that's what template files are for. If you want to completely encapsulate your header for some reason or another in seperate files, what you need is partials. You're going to do something like this:
<body>
<%= render :partial => "shared/header" %>
<%= yield %>
</body>
Which will render your header content, stored in /shared/_header.html.erb into the layout here.
Check out this guide here for more info

Conditional rendering in Ruby on Rails

Is it possible to render some part of the template if it is a certain page of the web site? Or is it also possible to include specific javascripts in application.html.erb layout if it is a certain page?
Maybe content_for can help you.
For example:
layout.html.erb
...
<head>
<%= yield :scripts %>
</head>
...
<%= yield %>
view.html.erb
...
<% content_for :scripts do %>
<script>..</script>
<% end %>
...
As an addendum to what railscard said I usually do this:
In the layout:
<%= stylesheet_link_tag content_for?(:stylesheets) ? yield(:stylesheets) : "application", :debug => Rails.env.development? %>
Then inside a view
<% content_for :stylesheets %> my_view.js <% end %>
That way you only have to set content_for if there is something special you want to change the top level file loaded from sprockets.

Rails render partial without entire html layout

Ok so I have a problem with rails and rendering partials. I have a layout called profile and inside of the profile layout I have all my js, stylesheets, etc included.
<html>
<head>
<title>Profile</title>
<%= javascript_include_tag "https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js" %>
<%= javascript_include_tag "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.10/jquery-ui.min.js" %>
<%= javascript_include_tag "application" %>
<%= stylesheet_link_tag "main" %>
<%= stylesheet_link_tag "reset" %>
<%= csrf_meta_tag %>
</head>
<body>
<%= yield %>
</body>
</html>
Inside of the yield tag(profile/index.html.erb) above is the following
<%= render :partial => 'pages/page', :layout => "layouts/default", :locals => {:page => #page } %>
Now in the pages/page view there are the same default tags such as css and js files. When i remove the css styles then I lose the styling for the pages/page view. Is there a way I can render a partial without recalling the same css and js files or what is a better way to go about doing something like so?
I always create the option to overwrite the stylesheets as follows:
<%= stylesheet_link_tag content_for?(:stylesheets) ? yield(:stylesheets) : "application", :debug => Rails.env.development? %>
Then inside a view
<% content_for :stylesheets %> some stuff or nothing in here <% end %>
That will let you specify in a view rendered in a layout you want no stylesheets and the same principle applies for javascripts.
That having been said if you are rendering a partial inside a layout that has an html tag and head etc. you should probably investigate if there is a better way to do what you are doing.
You need to pick one or the other: layout the original method call, or pass a layout to the partials. Doing both would be illogical.
There is a more thorough discussion here:
http://www.mikemayo.org/2012/rendering-a-collection-of-partials-with-content_for
I rarely see the usage of( or I am wondering if Rails support this usage... )
<!-- confirmed, this usage will cause error in Rails 3.2 -->
<%= render :partial => "some_partial", :layout => "some_layout" ... %>
I prefer to choose the specific layout in the controller:
def some_action
# some code
render :layout => "some_layout"
end
A partial is basically just a "slice of page" (like slice of cake... but in code form). It's designed to populate a small part of the page; typically one which will by dynamically updated depending on page variables.
Seems like you're confusing the purpose of layouts, views & partials in my opinion. If you want to dynamically load CSS / JS, put a "content_for" block in the profile views with a default layout, like this:
Layout
#layouts/default.rb
<html>
<head>
<title>Site Title</title>
<%= javascript_include_tag "https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js" %>
<%= javascript_include_tag "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.10/jquery-ui.min.js" %>
<%= javascript_include_tag "application" %>
<%= stylesheet_link_tag "main" %>
<%= stylesheet_link_tag "reset" %>
<%= yield :header_includes %>
<%= csrf_meta_tag %>
</head>
<body>
<%= yield %>
</body>
</html>
Views
#views/profiles/index.html.erb
<% content_for :header_includes do %>
<%= stylesheet "profile_custom_css" %>
<% end %>
Partial
Partials could be used to keep your code DRY & give the output of specific header files, like this:
Partial
#views/elements/_custom_header.rb
<% content_for :header_includes do %>
<% headers.each do |type, value| %>
<% if type == "java" %>
<%= javascript_include_tag value %>
<% else %>
<%= stylesheet_link_tag value %>
<% end %>
<% end %>
<% end %>
View
#views/profiles/index.html.erb
<%= render :partial => 'elements/custom_header', locals: { :headers => [["java", "profile_custom"], ["stylsheeet", "profile_custom"]] } %>
#Resume standard view code here
Layout
#layouts/default.rb
<html>
<head>
<title>Site Title</title>
<%= javascript_include_tag "https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js" %>
<%= javascript_include_tag "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.10/jquery-ui.min.js" %>
<%= javascript_include_tag "application" %>
<%= stylesheet_link_tag "main" %>
<%= stylesheet_link_tag "reset" %>
<%= yield :header_includes %>
<%= csrf_meta_tag %>
</head>
<body>
<%= yield %>
</body>
</html>
I've not tested passing the partial locals as a hash, so the syntax may be incorrect, but this is what we'd do to load up the required code. The added benefit is that content_for only yields content that has been defined (I.E you just have to include yield :custom_headers and it will only show if the content block is present)

the best way to have separate stylesheets for different actions in Rails

I have one app layout that includes app wide css stylesheets and js files, but some controller's actions need additional stylesheets that is used only for these action
s view? What is the best way to include them?
If your app is typically something like:
<html>
<head>
<%= stylesheet_link_tag 'application' -%>
<%= javascript_include_tag 'yui', 'application' -%>
</head>
<body>
<%= yield -%>
</body>
</html>
You can add other yield blocks wherever you like, named whatever you want. Typically I used this to include page-specific functionality wherever I like, even to the degree that maybe partials supply their own.
# layouts/application.html.erb
<html>
<head>
<%= stylesheet_link_tag 'application' -%>
<%= javascript_include_tag 'yui', 'application' -%>
<%= yield :head -%>
</head>
<body>
<%= yield -%>
</body>
</html>
# views/profiles/show.html.erb
<%= title("#{#user.name}'s Profile") -%>
<% content_for :head do -%>
<%= javascript_include_tag 'gallery' %>
<% end %>
<%= render #user.photos %>
So on and so forth...
For the javascript, one way to deal with this is using a <%= yield :javascript %> inside your the ... tag in your layout file. Then in your view code, you can use a <% content_for :javascript do %> ...put your javascript here ... <% end %>
This way, your javascript and your html erb code live in the same location.
Javascript that is used throughout the sight can be placed in a global file.

Resources