I'm trying to render the following partial:
<% #accepted.each do |question| %>
<div class="questions-container__content">
<div class="questions-container__accepted-content">
...
</div>
<%= render 'question_buttons', collection: #accepted %>
</div>
<% end %>
with _question_buttons.html.erb:
<div class="links-container__button-group" id="link-buttons">
<%= link_to "View submission", coin_question_path(question.coin, question.id), class: "primary-small","data-turbolinks"=>"false" %>
<%= link_to "Edit", edit_coin_question_path(question.coin, question.id), class: "primary-small","data-turbolinks"=>"false" %>
<% if !question.accepted? %>
<%= link_to "Activate" , activate_coin_question_path(question.coin, question.id), class: "primary-small","data-turbolinks"=>"false" %>
<% else %>
<%= link_to "Deactivate" , deactivate_coin_question_path(question.coin, question.id), class: "primary-small","data-turbolinks"=>"false" %>
<% end %>
<% if current_user.admin? %>
<%= link_to (question.rejected ? "Restore" : "Reject"), reject_coin_question_path(question.coin, question.id), class: "primary-small","data-turbolinks"=>"false" %>
<% end %>
</div>
I get the following error:
undefined local variable or method `question' for #<#<Class:0x00007fece6998d08>:0x00007fed02072bb8>
What am I doing wrong here?
I believe the issue is that you need to pass the question variable from each loop in the parent view through to the partial using locals which allows the partial to access it.
<%= render 'question_buttons', locals: { question: question } %>
First:
When rendering a collection, each item of the collection is passed to the partial as a local variable with the same name as partial itself. It means that for this call:
<%= render 'question_buttons', collection: #accepted %>
the partial question_buttons will be called for each item of #accepted array; that item will be available inside partial as question_buttons.
If you want to use another name for the item, for example question, you need to call it as:
<%= render 'question_buttons', collection: #accepted, as: :question %>
Another option -- just rename the partial to question:
<%= render 'question', collection: #accepted %>
Second:
In your code snippet rendering collection is called on each iteration of the loop over #accepted elements. If #accepted has 8 elements, for example, the partial will be rendered 8 times for each of these elements, ie 8 * 8 = 64 times in total. I suspect that it's not what you want to achieve. Your code looks like question_buttons partial needs to be rendered for each element of #accepted only once. In this case using collection param has no sense here. Just pass a local variable question into the partial:
<%= render 'question_buttons', question: question %>
Related
This is similar to this question but with a collection:
<div class="panel-body">
<%= render layout: 'today_items_list', locals: {items: #pos} do |po| %>
<% #output_buffer = ActionView::OutputBuffer.new %>
<%= link_to "##{po.id}", po %>
<%= po.supplier.name %>
<% end %>
</div>
with partial/layout:
.tableless_cell.no_padding
%h3.no_margin_vertical= title
%ul.no_margin_vertical
- for item in items
%li= yield(item)
This renders as you expect but if I omit the weird '#output_buffer = ActionView::OutputBuffer.new', the buffer is not cleared and the list is rendered this way:
<li>
#4833Supplier name
</li>
<li>
#4833Supplier name
#4835Supplier name 2
</li>
<li>
#4833Supplier name
#4835Supplier name 2
#4840Supplier name 3
</li>
Never clearing the buffer between block invocation. What am I missing here?
(Riding on Rails 3.2.22)
I don't have much experience with Rails 3.2; with newer versions, you're able to pass collections to partials:
<%= render #pos, layout: 'today_items_list' %>
#app/views/pos/_today_items_list.html.erb
.tableless_cell.no_padding
%h3.no_margin_vertical= title
%ul.no_margin_vertical
<%= yield %>
#app/views/post/_po.html.erb
<%= link_to "##{po.id}", po %>
<%= po.supplier.name %>
You can read more about collections etc (I presume for Rails 4+) here.
This is my .erb file;
<% if #comment.reviewer_notes && current_user.type == "User::Reviewer"%>
<% #comment.reviewer_notes.each do |reviewer_note| %>
<?= reviewer_note.rating %> <-- this "works" ie prints out rating on screen
<%= render 'partials/comments/form' %>
this is my .erb partial;
<div class="admin-rating stars clear">
<%= reviewer_note.rating %> <-- this does not work.
</div>
The error I get is;
undefined method `reviewer_rating' for #TipComment:0x007f8b38e29328>
How do I pass in reviewer_note.rating?
<%= render partial: 'reviewer_note_rating', locals: {reviewer_note: reviewer_note} %>
You should pass it as a variable to Partial.
<%= render 'partials/comments/form', note_rating: reviewer_note.rating %>
Assuming that the "books/book" partial below is being called from multiple locations (like: author#show view, categogories#show view, categories#index view) and i only want the votes partial called from the author#show view. That is, i want the books collection returned from the books partial (#upvoted_books) to each render the "votes/vote" partail so that authors are able to vote on a book from their author#show view. Is the following code or a variation of it sensible?
<%= render partial: "books/book", collection: #upvoted_books do |upvoted| %>
<%= render partial: "votes/vote", locals: {category: book.category, book: upvoted } %>
<% end %>
p.s: I have tried this particular code here and it doesnt work in my project but i was just wondering if something similar to it could work but it doesnt throw any apparent error either. Maybe i was just getting the syntax a bit mixed up. I alos know a few other ways to solve the same problem but i was looking for something more elegant. Thanks in anticipationm of your creative responses.
update:
Thanks #Deep, for your very insightful solution. What I have done to solve the problem before is calling the line below from "books/book" partial:
<% if defined?(#upvoted_books) && #upvoted_books.include?(book) %>
<%= render partial: "votes/vote", locals: {category: book.category, book: upvoted } %>
<% end %>
That works but i'm not sure it has some significant code-smell or if its syntatically awkward. What do you think?
Final update:
#Deep these are the views you asked for: This is my category#show view :
`<h1>Topics#show</h1>
<p><%= #category.title %></p>
<%= render partial: "books/form", locals: {topic: #category, book: Book.new} %>
<%= link_to "edit category", edit_author_category_path(#category.author, #category) %>
<p> Books you have Authored </p>
<%= render partial: "books/book", collection: #category.books %>`
And this is my books/_book.html.erb partial now
`<% if defined?(upvoted_book) && current_author.books.include?(upvoted_book) %>
<h5>Created by <%= upvoted_book.category.author.name || upvoted_book.category.author.email %> on <%= upvoted_book.created_at %></h>
<br>
<%= link_to upvoted_book.title, category_book_path(upvoted_book.category, upvoted_book) %>
<% if policy(Vote.new).create? %>
<%= render partial: "votes/vote", locals: {category: upvoted_book.category, book: upvoted_book} %>
<br>
<% end %>
<% else %>
<h5>Created by <%= book.category.author.name || book.category.author.email %> on <%= book.created_at %></h>
<br>
<%= link_to book.title, category_book_path(book.category, book) %>
<%= link_to "Remove book", category_book_path(book.category, book), method: :delete, data: { confirm: "Are you sure you want to delete this book?" } %>
<% end %>`
As you can see, i refer to local variables book and upvoted_book in the partial. This is how i called the partial from the author#show view : `
<%= render partial: "categories/form", locals: {category: Category.new, author: #author} %>
<p> Categories and Books you have Writen: </p>
<%= render partial: "categories/category", collection: #categories %>
<p> Books from all authors that you have Upvoted: </p>
<%= render partial: "books/book", collection: #upvoted_books, as: :upvoted_book %>
<br> `
Thanks for you wonderful insight again.
As you need vote partial to be rendered on each book and only in a single view, so what you can do is:
<%= render partial: "books/book", collection: #upvoted_books, locals: { vote: true } %>
Now in your partial book write down:
if vote
<%= render partial: "votes/vote", locals: {category: book.category, book: upvoted } %>
end
And make sure from rest of the places where you are rendering book partial pass locals: { vote: false } or else it will throw error. Or what you can do in the partial is:
vote ||= false
Or instead of using if vote you can use if defined?(vote), so there would be no burden to pass it from other pages.
Also I doubt you have some wrong locals, not sure may be so correct them. But using this you can call vote partial on a single view.
Hope this helps.
I have a common problem that normally I would solve with locals, but this time wont work.
I have the following block:
<% #user.followers.each do |follower| %>
<%= render "follower_card" %>
<% end %>
And the following partial:
<div class="row follower-card">
<%= image_tag follower.avatar_url(:smallthumb), class: "col-4 inline avatar_medium circle" %>
<ul class="col-8 inline">
<li><%= follower.name %></li>
<li><%= follower.location %></li>
<li class="lightgray small inline"><span class="bold"><%= follower.photos.count %></span> Spots</li> -
<li class="lightgray small inline"><span class="bold"><%= follower.albums.count %></span> Spotbooks</li>
</ul>
</div>
I'm getting the following error:
undefined local variable or method `follower' for #<#<Class:0x007fe791a4c8d0>:0x007fe799b14b98>
This should work (specifying the follower variable):
<%= render "follower_card", follower: follower %>
Anyway, I recommend you to use collection rendering for performance reasons. Take a look here: http://guides.rubyonrails.org/layouts_and_rendering.html. Should be something like:
<%= render "follower_card", collection: #user.followers %>
Related question: Render partial :collection => #array specify variable name
Note
Old syntax to pass variables to partials is also valid (verbose, but less elegant IMHO):
<%= render partial: "follower_card", locals: { follower: follower } %>
This is because you are not passing the variable to the partial. The scope of the partial is limited to itself, and you are not making follower available inside. You will have to use:
<% #user.followers.each do |follower| %>
<%= render "follower_card", locals: {follower: follower} %>
<% end %>
Is the proper way.
<%= render "follower_card", follower: follower %>
or
<%= render partial: "follower_card", locals: {follower: follower} %>
I am trying to create a checklist in rails using form_for. This checklist is taken from a table which I gained in the create action of my sign_ins controller:
#content = OrientationContent.where(site_id: session[:site_id])
In my view I want to use the form_for helper to iterate through the list in #content:
<%= form_for(:sign_ups ) do |f| %>
<% #content.each do |c| %>
<%= f.check_box nil %> <%= c %> <br>
<% end %>
<% end %>
However this is not working and it produces two square brackets on the page: [].
How do I go through the list and print the name while creating a check box on the left of it? The check box does not have any meaning or data, I just need it present for reference.
Solved:
In the controller, need to pluck an individual field:
#content = OrientationContent.where(site_id: 1).pluck(:content)
In the view, structure as so:
<%= form_for(:sign_ups) do |f| %>
<% #content.each do |c| %>
<%= f.check_box nil %> <%= c %> <br>
<% end %>
<% end %>