Why my partial won't receive parameters correctly? - ruby-on-rails

When rendering a partial called 'member', it says error
undefined local variable or method `user' for #<#:0x000000095ec8c0>
Why??
My codes are
View
<% #users.each do |user| %>
<%= render 'member', :locals => {:user => user} %>
<% end %>
Partial
<div class="chapter">
<p class="title">
<%= user.user_profile.nickname %>(<%= user.username %>)
</p>

You should use:
<%= render :partial => 'member', :locals => { :user => user } %>
Or just with:
<%= render 'member', :user => user %>

My advice is that you stick to the conventions whenever you can; everything will go a lot smoother for you if you do.
If you had a _user.html.erb partial, you could be using this rails convention
<% #users.each do |user| %>
<%= render user %>
<% end %>
But you can even shorten this more
<%= render #users %>
Huzzah!
I strongly suggest you check out the Layouts and Rendering Guide

Related

passing variable to simple form symbol

this is my _form_item partial in which I used symbol :order_item
<%= simple_form_for :order_item do |f| %>
.....
<% end %>
here is my view in which I want to render that partial:
<%= content_tag_for :tr , #order.order_items do |i| %>
<div class="hide">
<%= render :partial => "form_item" %>
</div>
<% end %>
How can I pass "i" object to :order_item?
UPDATE:
I prefer to keep it ":order_item" instead of changing it to something like "foo".
You should have:
<%= render partial: 'form_item', locals: {order_item: i} %>
or a shorthand:
<%= render 'form_item', order_item: i %>
And in your form_item partial you should have:
<%= simple_form_for order_item do |f| %>
...
Just do
<%= simple_form_for item do |f| %>
.
.
<% end %>
and render the partial via
<%= render :partial => 'form_item', :locals => { :item => i } %>
You can pass i as a locals to the partial like follows:
<%= render :partial => "form_item", :i => i %>
and you'll have i available in the _form_item partial.
Update:
Local variables passed to partials are variables and not symbols. You could keep the name order_item like follows:
<%= render :partial => "form_item", :order_item => i %>
And update your order_item partial as follows:
<%= simple_form_for order_item do |f| %>
.....
<% end %>
I think I understand why you do not want to change :order_item to just order_item. I think you are going to have to update your other calls to pass in local variable order_item where ever you are making a call to this partial.

Refactoring into partials in Rails

In page1, I use code A+B+C
In page2, I use code B+C
So when I make a partial, I realy have no idea in how to deal with this.
For example, In a Post-Comment system. I want to show #comments in 2 different pages. In the comment index page,
We show the post it belongs to. And in the post show page, We only have to show the comments content.(Since there is no need to show the comment.post again)
#Comment Index Page
<% #comments.each do |comment| %>
<%= comment.post %>
<%= comment.author %>
<%= comment.content %>
<% end %>
..
#Post Show Page
<% #comments.each do |comment| %>
<%= comment.author %>
<%= comment.content %>
<% end %>
So, how do I make a partial to reuse the code? Perhaps like this? But this there more elegant way of doing this?
#Comment Index Page
<% #comments.each do |comment| %>
<%= comment.post %>
<%= render comment %>
<% end %>
#Post Show Page
<% #comments.each do |comment| %>
<%= render comment %>
<% end %>
Updated:
I adopt the local variable approach, and update my code like:
# partial
<% if include_topic %>
<div class="Topic">
<h5><%= link_to "#{comment.topic.content}", comment.topic %></h5>
</div>
<% end %>
#Index
<%= render #comments, :locals => {:include_topic => true } %>
But I get undefined local variable or method `include_topic' for #<#
I just find nowhere to debug this issue
Your partial:
<%= comment.post if include_post %>
<%= comment.author %>
<%= comment.content %>
your code:
#index page
<%= render :partial => "partial_path", :collection => #comments, :as => :comment, :locals => {:include_post => true } %>
#show page
<%= render :partial => "partial_path", :collection => #comments, :as => :comment, :locals => {:include_post => false } %>
Syntax could be much shorter but it depends whether or not you stick to rails conventions see doc.
Sidenote: I don't like 1.8.7 syntax
In the partial,
<% comments.each do |comment| %>
<%= comment.post if params[:controller] == "comments" %>
<%= comment.author %>
<%= comment.content %>
<% end %>
and now render this partial in both comments/index and posts/show pages by specifying the comments as a local variable.

Check for nil?, Blank?

I have a model and for some reason I am trying to tell rails if there is nothing created then render add a new show link.
<% if #show != blank? %>
<%= link_to 'Add a new show', new_show_path %></br>
<% else %>
<%= render(:partial => 'shows/show', :locals => {:show => #profile.shows.last}) %>
<% end %>
It adds the Add a new show link but once a show is created I still only see the link and not the partial. If I create the show and put the render at top like so then I can see it but if i delete the show it returns an error.
I've tried these also
<% if #show.present? %>
<%= render(:partial => 'shows/show', :locals => {:show => #profile.shows.last}) %>
<% else %>
<%= link_to 'Add a new show', new_show_path %></br>
<% end %>
<% if #show.blank? %>
<%= link_to 'Add a new show', new_show_path %></br>
<% else %>
<%= render(:partial => 'shows/show', :locals => {:show => #profile.shows.last}) %>
<% end %>
<% if #{model} nil? %>
<%= link_to 'Add a new show', new_show_path %></br>
<% else %>
<%= render(:partial => 'shows/show', :locals => {:show => #profile.shows.last}) %>
<% end %>
and it seems to never give me what I am looking for on both ends. It ethiers shows me the link and nevers shows the partial once created or it shows the partial but when I delete it it gives me an error.
How can I tell rails that if there is no shows created to render the add new link and once there is a show created to render the partial?
Are you actually filtering this by profile? It looks like you're rendering a page for the last show of a profile. (#profile.shows.last)
<% show = #profile.shows.last %>
<% if show.blank? %>
<%= link_to 'Add a new show', new_show_path %>
<br />
<% else %>
<%= render 'shows/show', :show => show %>
<% end %>
Use the .blank? method for the global variable you're trying to tell if it's empty. If its an array or hash. Use .nil? If its supposed to be anything else.

Pass a variable into a partial, rails 3?

I have a loop like such:
<% #posts.each do |post| %>
<% render middle %>
<% end %>
Then in my middle partial, how do I access the current post?
Try this:
<% #posts.each do |post| %>
<%= render 'middle', :post => post %>
<% end %>
Like this you'll have a local variable post available within the partial.
Give it to the partial as a local variable
<%= render :partial => 'middle', :locals => { :post => post } %>
Of course, rails also has a shortcut for rendering collections:
<%= render :partial => 'post', :collection => #posts %>
In this case it will call the partial post for every post with a local variable 'post'
You can even render a spacer template between each post:
<%= render :partial => 'post', :collection => #posts, :spacer_template => 'post_divider' %>
<% #posts.each do |post| %>
<% render middle, :post => post %>
<% end %>
You can now access post as the local variable post in the partial
Replace <%= render middle %> with <%= render middle, :post => post %>. Then in your middle partial, you can access the post variable.
You can replace the entire each block with this:
<%= render partial: "product", collection: #posts %>
Or even shorter:
<%= render #posts %>
Full documentation (section 3.2)
https://guides.rubyonrails.org/action_view_overview.html

How can I make three partials into just one in rails where the :collection is the same?

I have three partials that I'd like to consolidate into one. They share the same collection, but each gets passed its own :local variable. Those variables are used for specific Models, so as a result, I have three different calls to the partial and three different partials.
Here's the repetitive code:
<% for email in campaign.emails %>
<h4><%= link_to email.title, email %> <%= email.days %> days</h4>
<% #contacts= campaign.contacts.find(:all, :order => "date_entered ASC" )%> <!--contacts collection-->
<!-- render the information for each contact -->
<%= render :partial => "contact_email",
:collection => #contacts,
:locals => {:email => email} %>
<% end %>
Calls in this Campaign:
<% for call in campaign.calls %>
<h4><%= link_to call.title, call %> <%= call.days %> days</h4>
<% #contacts= campaign.contacts.find(:all, :order => "date_entered ASC" )%> <!--contacts collection-->
<!-- render the information for each contact -->
<%= render :partial => "contact_call",
:collection => #contacts,
:locals => {:call => call} %>
<% end %>
Letters in this Campaign:
<% for letter in campaign.letters %>
<h4><%= link_to letter.title, letter %> <%= letter.days %> days</h4>
<% #contacts= campaign.contacts.find(:all, :order => "date_entered ASC" )%> <!--contacts collection-->
<!-- render the information for each contact -->
<%= render :partial => "contact_letter",
:collection => #contacts,
:locals => {:letter => letter} %>
<% end %>
An example of one of the partials is as follows:
<
div id="contact_email_partial">
<% if from_today(contact_email, email.days) < 0 %>
<% if show_status(contact_email, email) == 'no status'%>
<p> <%= full_name(contact_email) %>
<% unless contact_email.statuses.empty?%>
(<%= contact_email.statuses.find(:last).status%>)
<% end %>
is <%= from_today(contact_email,email.days).abs%> days overdue:
<%= do_event(contact_email, email) %>
<%= link_to_remote "Skip Email Remote",
:url => skip_contact_email_url(contact_email,email),
:update => "update-area-#{contact_email.id}-#{email.id}" %>
<span id='update-area-<%="#{contact_email.id}-#{email.id}"%>'> </span>
<% end %>
<% end %>
</div>
And here is the other partial...similar, eh? Need help making it DRY!
<% if (from_today(contact_call, call.days) < 0) %>
<% if show_status(contact_call, call) == 'no status'%>
<p> <%= full_name(contact_call) %>
<% unless contact_call.statuses.empty?%>
(<%= contact_call.statuses.find(:last).status%>)
<% end %>
is <%= from_today(contact_call,call.days).abs%> days overdue:
<%= do_event(contact_call, call) %>
<%= contact_call.phone %>
</p>
<% end %>
<% end %>
For the local variables, the key you select when passing the locals hash is the name the variable will have in the partial. So you could do this in your repetitive code:
<% for email in campaign.emails %>
<h4><%= link_to email.title, email %> <%= email.days %> days</h4>
<% #contacts= campaign.contacts.find(:all, :order => "date_entered ASC" )%> <!--contacts collection-->
<!-- render the information for each contact -->
<%= render :partial => "contact",
:collection => #contacts,
:locals => {:objt => email,
:url_method => "skip_#{class}_url".to_sym } %>
<% end %>
Calls in this Campaign:
<% for call in campaign.calls %>
<h4><%= link_to call.title, call %> <%= call.days %> days</h4>
<% #contacts= campaign.contacts.find(:all, :order => "date_entered ASC" )%> <!--contacts collection-->
<!-- render the information for each contact -->
<%= render :partial => "contact",
:collection => #contacts,
:locals => {:objt => call,
:url_method => "skip_#{class}_url".to_sym } %>
<% end %>
Letters in this Campaign:
<% for letter in campaign.letters %>
<h4><%= link_to letter.title, letter %> <%= letter.days %> days</h4>
<% #contacts= campaign.contacts.find(:all, :order => "date_entered ASC" )%> <!--contacts collection-->
<!-- render the information for each contact -->
<%= render :partial => "contact",
:collection => #contacts,
:locals => {:objt => letter,
:url_method => "skip_#{class}_url".to_sym } %>
<% end %>
Since in the partial we don't really know the class of the object we need to render, I'm creating a symbol representing the method you need to call to build the URL. We'll invoke this in the partial using a bit of send magic.
Notice the partial has been renamed simply "contact" (_contact.html.erb), and I'm assigning email, call and letter in turn to a variable called objt, that will be accessible from the partial.
For the partial (_contact.html.erb):
<div id="contact_partial">
<% if from_today(contact, objt.days) < 0 %>
<% if show_status(contact, objt) == 'no status'%>
<p> <%= full_name(contact) %>
<% unless contact.statuses.empty?%>
(<%= contact.statuses.find(:last).status%>)
<% end %>
is <%= from_today(contact,objt.days).abs%> days overdue:
<%= do_event(contact, objt) %>
<%= link_to_remote "Skip Email Remote",
:url => send(url_method,contact,objt),
:update => "update-area-#{contact.id}-#{objt.id}" %>
<span id='update-area-<%="#{contact.id}-#{objt.id}"%>'> </span>
<% end %>
<% end %>
</div>
Notice how, instead of calling the skip_email_url method directly, we use "send" to invoke a method named in the first parameter (in this case, url_method, a local passed from the invoking view), and further, we pass this method the additional parameters (in this case, contact and objt). Just make sure the method named in url_method does effectively take two parameters.

Resources