I have a short question to help me understand Rails partials. I am new to RoR and just working through Agile Web Development with Rails. I am in Iteration F1 if you have the same book.
When i am not using partials, the show.html.erb from the carts looks like this:
<% if notice %>
<p id="notice"><%= notice %></p>
<% end %>
<!-- START_HIGHLIGHT -->
<h2>Your Cart</h2>
<table>
<!-- END_HIGHLIGHT -->
<% #cart.line_items.each do |item| %>
<!-- START_HIGHLIGHT -->
<tr>
<td><%= item.quantity %>×</td>
<td><%= item.product.title %></td>
<td class="item_price"><%= number_to_currency(item.total_price) %></td>
</tr>
<!-- END_HIGHLIGHT -->
<% end %>
<!-- START_HIGHLIGHT -->
<tr class="total_line">
<td colspan="2">Total</td>
<td class="total_cell"><%= number_to_currency(#cart.total_price) %></td>
</tr>
<!-- END_HIGHLIGHT -->
<!-- START_HIGHLIGHT -->
</table>
<!-- END_HIGHLIGHT -->
<%= button_to 'Empty cart', #cart, method: :delete,
data: { confirm: 'Are you sure?' } %>
Then, when I start to use partials, I created a class called _cart.html.erb and put this in it:
<h2>Your Cart</h2>
<table>
<%= render(cart.line_items) %>
<tr class="total_line">
<td colspan="2">Total</td>
<td class="total_cell"><%= number_to_currency(cart.total_price) %></td>
</tr>
</table>
<%= button_to 'Empty cart', cart, method: :delete, data: { confirm: 'Are you sure?' } %>
And modified my show.html.erb to this:
<% if notice %>
<p id="notice"><%= notice %></p>
<% end %>
<%= render(#cart) %>
So, my confusion is now, why do I have to use #cart.something when I dont have partials. For my understanding it was the model I was using which called carts.rb. So, when I then create a partial, then I just simply use cart instead of #cart and the partial is still using the model?
But why then I use render(#cart)? Is this command then just using my partial _cart.html.erb?
can anybody help me to complete my understanding of it? probably it is like it is, but i confuses me a little bit at the moment :)
When you say render(#cart), what's really happening behind the scenes is Rails is making a lot of assumptions for you based on the conventions of how Rails generally works.
Let's start off with the #cart variable. This is an instance variable, which is a variable that's accessible to anything inside your controller. Views have a special relationship with controllers, so instance variables defined within a controller method are available within the view.
You could use #cart within your partial, and everything would work fine in this case. But it's generally a bad idea - you want partials to be reusable in different spots, and assuming that an instance variable exists introduces coupling between your controller and the partial.
The solution that Rails provides is the ability to pass local variables to a partial. Remember how I said that render(#cart) is a shortcut? What's really happening behind the scenes is this:
render partial: 'carts/cart', locals: { cart: #cart }
Because you're following Rails conventions, Rails can make the following assumptions:
The partial for a Cart is located in app/views/carts/_cart.html.erb
That partial is going to use a local variable named cart, which is passed to the method.
So as a result, the following:
render #cart
has the same effect as the more verbose line above.
Related
I'm using tables to list recorded from database in index templates, And as usual the last three table cells are used for the links of Show, Edit and Destroy the Object.
../users/index.html.erb
<table>
...
<% #users.each do |user| %>
<tr>
...
<td><%= link_to 'Show', user %></td>
<td><%= link_to 'Edit', edit_user_path(user) %></td>
<td><%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
Anyway, I was trying to replace those links text to some Bootstrap's glyph icons, And I succeeded but It got messy so I thought it better to put it in a partial with a variable to be shared with all index templates that use the same table layout.
../shared/_editLinks.html.erb
<td>
<%= link_to dist do %>
<span class="glyphicon glyphicon-eye-open"></span>
<% end %>
</td>
<td>
<%= link_to send("edit_#{dist}_path(#{dist})") do %>
<span class="glyphicon glyphicon-edit"></span>
<% end %>
</td>
<td>
<%= link_to dist, method: :delete, data: { confirm: 'Are you sure?' } do %>
<span class="glyphicon glyphicon-remove"></span>
<% end %>
</td>
Then To use the following code line to render the partial in the index table. Passing the resource name as variable.
<%= render 'editLinks', dist: user %>
Then the first and the last links seems to work fine but I got this error around the middle -Edit- link.
undefined method `edit_user_path(#<User:0x007f611ab015a8>)' for #<#<Class:0x007f611a7064d0>:0x007f611ab143b0>
Can you tell me what causes this error and how to get it work?
The lines causing errors are because you're trying to treat an object like a string.
Because the _path helpers are typically snake_case, you can use the underscore method on the object's class name like so:
<%= link_to send("edit_#{dist.class.name.underscore}_path", dist) do %>
As pointed out by Deepak, you also can be providing the dist object as the second argument to send. Otherwise, you'll end up with a similar error because you'd again be treating the object as a value that can be coerced into a string.
Pass param to route/method separated by comma
<%= link_to send("edit_#{dist.class.name.underscore}_path", dist) do %>
send method syntax
I have a table and in my code on my html.erb file,
<td class="pstn-column"><%= a.lenders.pluck(:code).join(", ") %></td>
This returns the result in this format
Lender1, Lender2, Lender3
How do i make the result to look like this on the table
Lender1
Lender2
Lender3
I am using rails
Any help appreciated
<% a.lenders.pluck(:code).each do |lender| -%>
<td class="pstn-column"><%= lender %></td>
<% end -%>
I assumed that you need each element in a separate cell.
Just Try this
This code will add br tag after each element
<td class="pstn-column"><%= a.lenders.pluck(:code).join('<br />').html_safe %></td>
or, this will add newline character after each element
<td class="pstn-column"><%= a.lenders.pluck(:code).join("\n") %></td>
Create a new partial and pass the collection to the renderer.
_lender.html.erb
<tr><td><%= lender %></td></tr>
view.html.erb
<%= render #lenders %>
# Or
<%= render partial: 'lender', collection: #lenders %>
controller.rb
#lenders = a.lenders.pluck(:code)
I would make a list of lenders, since that seems to resemble the result you are trying to achieve
<td>
<ul>
<% a.lenders.pluck(:code).each do |lender_code| %>
<li><%= lender_code %></li>
<% end %>
</ul>
</td>
If you want to, the bullets can be removed trough CSS, using <ul style='list-style: none;'>
This question already has answers here:
Rails: An elegant way to display a message when there are no elements in database
(10 answers)
Closed 8 years ago.
I'm a newbie at Rails and I'm having trouble wrapping my head around refactoring logic from views. Let's say I have a simple Post model. In the index view, I want specific content to be displayed if there are posts or not. Basically, if there are any posts, display this specific content or else this other content.
Here is my index.html.erb view for Posts:
<div class="content">
<% if #posts.any? %>
<table>
<thead>
<tr>
<th>Title</th>
<th>Content</th>
</tr>
</thead>
<tbody>
<% #posts.each do |post| %>
<tr>
<td><%= post.title %></td>
<td><%= post.content %></td>
</tr>
<% end %>
</tbody>
</table>
<% else %>
<p>There are no posts!</p>
<% end %>
</div>
Now, the way I refactored this was by creating a couple of helpers and partials like so:
posts_helper.rb (which renders the partials according to the if logic):
module PostsHelper
def posts_any
if #posts.any?
render 'this_content'
else
render 'this_other_content'
end
end
end
In the partials, I just used the exact content in the if else statement.
_this_content.html.erb partial:
<table>
<thead>
<tr>
<th>Title</th>
<th>Content</th>
</tr>
</thead>
<tbody>
<% #posts.each do |post| %>
<tr>
<td><%= post.title %></td>
<td><%= post.content %></td>
</tr>
<% end %>
</tbody>
</table>
_this_other_content.html.erb partial:
<p>There are no posts!</p>
Finally, the refactored index.html.erb (which would call the helper method):
<div class="content">
<%= posts_any %>
</div>
The problem is, I'm just not convinced that this is the correct Rails way of refactoring. If any of you could shed some light on this, I would highly appreciate it!
Thanks!
You're doing it right, and better than many people I know. :)
A few minor adjustments...
I would move the render from the helper to the erb, and just use the helper to return the right name of what to render.
Your erb code and helper code:
<%= posts_any %>
def posts_any
if #posts.any?
render 'this_content'
else
render 'this_other_content'
end
end
I suggest:
<%= render posts_any %>
def posts_any
#posts.any? ? 'this_content' : 'this_other_content'
end
Next, I personally like to render a collection using a partial.
Yours:
<% #posts.each do |post| %>
I suggest:
<%= render partial: "post", collection: #posts %>
And in the comment below, user kyledecot suggests even terser:
<%= render #posts %>
Then create the file _post.html.erb like this:
<tr>
<td><%= post.title %></td>
<td><%= post.content %></td>
</tr>
Some developers think that it's overkill to render a collection using a partial, in the case where the partial is not used anywhere else.
I personally think it's helpful, and especially useful when a project has multiple coders some of whom may be changing the table row data results.
I have an application where I want to render the menu using "content_for" as well as a left navigation bar and then the rest be the body of my document. However, in my left bar and menu regions, the html markup is being escaped. I saw a post regarding using raw before the yield, but that didn't help.
After spending quite some time trying to diagnose it within the real app, I created a VERY simple test and was able to get it to do the same with minimal code. Here is what I have:
layouts.application.erb
<body>
<section id="page">
<header>
<nav class="clear"><%= raw yield :navigation %></nav>
</header>
<%= yield %>
</section>
</body>
</html>
pages/index.html.erb
<% content_for :navigation do %>
<ul><li><%= link_to 'New page', new_page_path %></li></ul>
<% end %>
<h1>Listing pages</h1>
<table>
<tr>
<th>Title</th>
<th>Body</th>
</tr>
<% #pages.each do |page| %>
<tr>
<td><%=h page.title %></td>
<td><%=h page.body %></td>
<td><%= link_to 'Show', page %></td>
<td><%= link_to 'Edit', edit_page_path(page) %></td>
<td><%= link_to 'Destroy', page, :confirm => 'Are you sure?', :method => :delete %></td>
</tr>
<% end %>
</table>
When I hit the page in a browser, the navigation part is not escaped properly (actually the link is, but not the list, which is kinda important with menus:) )
This is from a brand new rails project using scaffold generated code which was modified only to move the default link up into the navigation section (and adding that piece in).
The escaping is happening when you set aside the content, not when you display it. Try using raw within content_for:
<% content_for raw :navigation do %>
I'm fairly new to Rails.
What is the best way to design/structure a multi-page form in Rails? I would like the form to create a new record in the database immediately when the first page of the form is submitted, and for each subsequent page of the form to update that record in the database.
The reason I want the record created immediately after the first page is submitted is so that there can be the notion of an unfinished record that the user comes back to later to finish.
Once created, I would like to allow the user to edit any part of the model by going directly to that section.
I know enough Rails where if you guide me with the best way to structure this conceptually, I should be able to figure out the code myself.
Thank you.
I have a multi-step signup process that works this way. I create the record the first time and then the other steps are edit/updates on that record. I use multiple controllers for this; it is a much cleaner approach than trying to cram all the logic into one controller action (although you could use multiple actions from the same controller and it would work just as well, but don't forget to create routes for your custom actions). This approach makes validation more difficult for the data added in steps after the first, but you can always add your own errors by calling errors.add on your model, essentially rolling your own validations. You can also write logic in your sessions controller to direct the user back to the same step in the multi-step form if they return later and have not completed it.
Ryan Bates explains this in one of his Railscasts => MultiSteps Forms
I've inherited a 'multi-page' form along those lines - but it was built for Rails 2.2 and I'm only just adapting the approach for Rails 3.
Essentially we used a tabbed layout with the entire form in one view - although this approach was heavily weighted towards one controller in Rails 2.2 I think it can be broken down better.
The layout meant that each section of the form could be accessed by the tabs - but each tabbed section also had a link_to action to the next section, at the bottom of that section (section A -> section B, for example) that saved the entire form each time you moved onto a new section - I've heavily edited the view just to give an idea but if it's a new form it will only reveal each section after the submit button for each section has been pressed.
<ul id="tabs">
<li>Section A</li>
<li>Section B</li>
<li>Section C</li>
<li>Section D</li>
<li>Section E</li>
<li>Section F</li>
<li>Section G</li>
<li>Section H</li>
<li>Section I</li>
<li>Section J</li>
</ul>
<%=hidden_field_tag 'active_fabtabulous_tab'%>
<% form_for(#detail) do |f| %>
<%= f.error_messages %>
<div class="panel" id="SectionA">
<b><u>Section A: Questionnaire Details</u></b>
<br></br>
<table>
<tr>
<td><div id="field_name">Questionnaire received on (dd/mm/yyyy):</div></td>
<td><%= date_select("questionnaire", :received_on, :order=>[:day,:month,:year],:use_month_numbers=>true,:start_year=>Date.today.year,:end_year=>2008,:include_blank => true) %></td>
</tr>
<tr>
<td><div id="field_name">Interviewer name:</div></td>
<td><%=text_field("questionnaire",:intervieweename)%></td>
</tr>
</table><!-- end questionnaire div -->
<%= f.submit "SectionB" , :class => "questButton" %>
</div>
<!--- Page 2 --->
<div class="panel" id="SectionB">
<b><u>Section B: Case Classification</u></b>
<br></br>
<% fields_for :patient, #patient do |p| %>
<table>
<tr>
<td class="sectionA_is_this_case"><div id="field_name">Epidemiology definition:</div></td>
<td><%= #patient.epidef %>
</td>
</tr>
</table>
<% end %>
<table>
<tr>
<% fields_for :patient, #patient do |p| %>
<td><div id="field_name">Asymptomatic:</div></td>
<td><% if #patient.asymptomatic %>Yes<% else %>No<% end %></td>
<% end %>
<tr>
<tr>
<td><div id="field_name">Investigation is:</div></td>
<td><%=select("detail", "invstatus", INVESTIGATION_IS)%></td>
</tr>
<tr>
<td><div id="field_name">Outbreak keyword or number:</div></td>
<td><%= f.text_field :outbreakid ,:cols => 40, :rows => 1 %></td>
</tr>
</table>
</div>
<%= f.submit "SectionC" , :class => "questButton" %>
</div>