Application.html.erb template inheritance - ruby-on-rails

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

Related

Rails partial for collection, only display certain things for first element

I have a collection of elements I'm rendering in a partial, but I only want to display a certain element with the very first element. My specific instance is displaying email addresses but I only want the email icon to show once next to the first instance (similar to how the Android Contacts app does).
I have a very "hacky" solution that uses instance variables in the view, which is not a good practice. But I'm struggling to find a cleaner way to implement what I want.
The controller:
#email_addresses = EmailAddress.order(:primary) # primary is a boolean value
The partial:
# views/email_addresses/_email_address.html.erb
<div class="email-address">
<% unless #email_icon_displayed
<% #email_icon_displayed = true %>
<div class="email-address-icon">
<span class="icon email"></span>
</div>
<% end %>
<div class="email-address-value">
<%= email_address.value %>
</div>
</div>
Calling partial in view:
<%= render partial: "email_addresses/email_address", collection: #email_addresses %>
This works properly and only displays the email icon for the first element, but instance variables in the view seems like a bad idea.
This may be a little late, but I had the same goal and I achieved it by using a "hidden" counter variable in Rails partial collections.
I called my partial collection like this:
<%= render partial: "questions/possible_answer",
collection: question.possible_answers, as: 'value' %>
And inside my partial I can access the variable value_counter, which increments for each partial. So to run something with the first element only, I did it like this:
if value_counter == 0
#do something
end
I think your case you would need to access it like this: email_address_counter
Found this solution here: https://coderwall.com/p/t0no0g/render-partial-with-collection-has-hidden-index

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

How Do I "Extend" a view in Rails

So I'm working on an open source project and due to different versions, there's the issue where I can't count on there being a controller for a view. Instead this email would be send out via a rake task for one version and a few others would done via a controller. Now you understand why I'm asking a bad practice question...
I have a layout for a view. Does anyone know a way to specify what the layout is for the view within the view. Some pseudo-code:
<%= extends 'layout/test_mailer` %>
<h1> Hey there! </h1>
And the layout would have the usual yield within it.
I hope I'm explaining the problem good enough.
<%= render partial: "hey_page", layout: "layout/test_mailer" %>
Check part 3.4.3 Partial Layouts at RailsGuides.
I think using yield and content_for should solve the problem. [Guides]
# my_layout.html.erb
<%= yield :mail_view %>
# my_mail_view.html.erb
<%= content_for :mail_view do %>
<!-- html -->
<% end %>
Of-course, if you are using params to get the layout, this would be a wrong answer.
Then, you can also use:
<%= render partial: "link_area", layout: "graybar" %>
You can use
//controller action
def index
render layout: test_mailer
end
//view, index.html.erb
<h1> Hey there! </h1>
//view, layout/test_mail.html.erb
<html>....layout for you test mail
<% yield %>
</html>

Where to put repeating display code for views in a Ruby on Rails app?

I have a Note model, which can contain have either an image link attachment (linktype = "image" or some text (linktype = "text). When I display the notes, the method of display changes depending on the linktype. An example is:
<% #notes.each do |q| %>
<h2 class="title"><%= q.name %></h2>
<% if q.linktype == "image"%>
<img src="<%= q.link %>" />
<% elsif q.linktype == "text"%>
<%= q.text %>
<% end %>
<% emd %>
I have to display the notes in a few different views in my site, so rather than have to repeat the viewing code multiple times, I want to have it in one place and refer to it from different views.
Should I do this in the application helper? If so, do I put the display code, like the code above, directly into the helper, or is there a better way? Thanks for reading.
For repeating view code that has nothing to do with some entity (is not, say, users/show.html.erb) make a widgets folder and write your partial there. I put in my widgets nav-bars and such.
/app/views/widgets/widget1.html.erb
/app/views/widgets/widget2.html.erb
...
# some_view.html.erb
<%= render :partial => 'widgets/widget1' %>
In an abstract way, I make the difference between helpers and this kind of partials as so:
helpers are for view-related logic (iterate in a special way etc)
view widgets are data image, they just match holes with data

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

Resources