I'm having trouble with attempting to render a partial within a loop. Essentially, I have an app where events are created, people join the event, and for each event, attendees have a list of items they will bring which they can select from their own inventory of items.
In my show.html.erb for Events:
<% #event.attendees.each do |user| %>
<div class="col-md-4">
<h4><%= user.first_name %> <%= user.last_name %></h4>
<% if user.event_items.any? %>
<div class="event-item-list">
<% user.event_items.each do |eventitem| %>
<div class="event-item-div" >
<p class="event-item-title"><%= eventitem.item.title %></p>
</div>
<% end %>
<% end %>
</div>
<% if user == current_user %>
<%= render 'event_items/form' %>
<% end %>
</div>
<% end %>
This works and shows the title of each event item that is added to the list.
However, if I want to move the content of the P tag to a partial, I get "undefined local variable or method `eventitem'". Which doesn't make sense to me since I would assume that whatever is passed in as a partial in that loop would be treated the same as if I just left that P tag content in there. At this point, all I have in the partial would be:
<p class="event-item-title><%= eventitem.item.title %><p>
Any insight would be appreciated.
Partials don't inherit local variables automagically, you have to define them. According to Rails Guides to pass local variables to a partial you need to set them in the locals hash
<%= render 'event_items/form', locals: {eventitem: eventitem} %>
Related
Rails beginner project
In a view that I want to show all results from two different models (MediaLink & MediaCollection)
I have successfully created a two dimensional array #ranked_media that holds
[0] is id from table
[2] is total_points
[5] is class name as a string.
Being that they are pulled from 2 different tables, the id can be repeated twice, but won't have the same class name if id are identical.
In my view (pages/media.html.erb) :
<div class="container">
<% #ranked_media.each do |media| %>
<% if media[5] == 'MediaCollection' %>
<%= render 'media_collection_show' %>
<% else %>
<%= render 'media_link_show' %>
<% end %>
<% end %>
</div>
partial _media_collection_show.html.erb :
<h2 class="text-center mt-4 text-white">
is a MEDIA COLLECTION of class :: <%= #media_collections.class %>
</h2>
partial _media_link_show.html.erb :
<h2 class="text-center mt-4 text-white">
is a MEDIA LINK of class :: <%= #media_links.class %>
</h2>
At this point all is fine. The block is being generated 5 times and applies the output according to the each block. The partials also outputs the class name to make sure they all work.
My Problem
However, I can add this to the view (3rd line is the change) :
<div class="container">
<% #ranked_media.each do |media| %>
<%= media %>
<% if media[5] == 'MediaCollection' %>
<%= render 'media_collection_show' %>
<% else %>
<%= render 'media_link_show' %>
<% end %>
<% end %>
</div>
And it outputs media object.
But if try that in any of the partials like this :
<h2 class="text-center mt-4 text-white">
is a MEDIA LINK of class :: <%= #media_links.class %>
<%= media %>
</h2>
I get NameError in Pages#media
undefined local variable or method `media'
How can I access the media block element inside these two partials?
By sending in local variables to the partials: <%= render 'media_link_show', media: media %>. In the partial you'd access it like so:
<h2 class="text-center mt-4 text-white">
is a MEDIA Object of class :: <%= media.class %>
</h2>
Note the lack of #; in general it's bad form to access instance
variables in partials.
Your third line (<%= media %>) also does nothing for the functionality, and can safely be removed.
Edit: When a controller does #items = ... in an action, it sets #items as an instance variable; any view rendered from that action has access to that value, which is why your #ranked_media can be looped over.
Partials are meant to be re-used, and not necessarily by the same view/controller, so if a partial accesses an instance variable, like your _media_collection_show.html.erb does, then any view/controller that uses that partial will need to set the #media_collections variable.
To avoid this (a controller action should strive to only set one instance variable), you can instead inject local variables into a partial: <%= render "partial_name", items: #items %>. Here, we're setting the local variable items to be the value of #items. By doing this, any view that uses the partial can send in their own items into the partial, without the need for the controller to set a "magical variable" #items. You could, for example, do: <%= render "partial_name", items: [1, 2, 3] %>. You've decoupled the partial from the controller.
Rails each do method is acting strangely and I do not know why.
controller
def index
#fabric_guides = FabricGuide.with_attached_image.all.order(:name)
end
index.html.erb
<div class="guide-items">
<%= #fabric_guides.each do |fabric| %>
<div class="guide-container">
<%= link_to fabric_guide_path(slug: fabric.slug) do %>
<%= image_tag fabric.image if fabric.image.attached? %>
<% end %>
<div class="guide-info">
<p class="g-name">
<%= link_to fabric.name,
fabric_guide_path(slug: fabric.slug) %>
</p>
</div>
</div>
<% end %>
</div>
I have two FabricGuide records so I expect two "guide-container" but I get three. Or more precisely I get two guide containers and a third block of text containing all the content from the last FabricGuide record.
I have almost an identical setup for articles and have never encountered this problem. I'd happily share more information if needed. Thank you!
Please remove = equal sign from your each loop of view code
like below :-
<% #fabric_guides.each do |fabric| %>
...
...
<% end %>
you have used this <%= #fabric_guides.each do |fabric| %> in your view that's why it shows all record in DOM.
The expression for erb tags is <% %>
now if we want to print that tag too then we apply <%= %>
In my rails category show controller for categories I have it setup like this
def show
#categories = Category.find_by(params[:name])
end
But when I visit this controller it returns all records of products found in the category instead of single category.
Here is the code in my view controller for category
<div class="grid">
<% #categories.products.each do |product| %>
<%= link_to product_path(id: product.slug, category_name: product.category.name), class: "card" do %>
<div class="product-image">
<%= image_tag product.productpic.url if product.productpic? %>
</div>
<div class="product-text">
<h2 class="product-title"> <%= product.name %></h2>
<h3 class="product-price">£<%= product.price %></h3>
</div>
<% end %>
<% end %>
</div>
What am i doing wrong here?
First of all, for security purposes, you should never trust the params hash to retrieve records. Rails will "make the data safe" if you use a hash as your arguments. Use this code below:
def show
#category = Category.find_by(name: params[:name])
end
Second, usually on a show page, you only want to retrieve one record and therefore the variable should be named as singular. I corrected that above.
Third, it helps if you use proper indenting when posting examples. It makes it easier for us to help you.
Fourth, the line below (I changed #categories to #category) is basically saying: "Now that I have this single category, find all the products associated with it in the products table and put them into the |product| variable for iteration"
<% #category.products.each do |product| %>
I'm not sure what you want to do with the category, but if you keep this line of code, it will always show you all the products. Maybe you only want to show the most recent 3, in which case you could do something like this:
In your controller:
def show
#category = Category.find_by(name: params[:name])
#recent_products = #category.products.order(created_at: :desc).limit(3)
end
In your view:
<div class="grid">
<% #recent_products.each do |product| %>
<%= link_to product_path(id: product.slug, category_name: product.category.name), class: "card" do %>
<div class="product-image">
<%= image_tag product.productpic.url if product.productpic? %>
</div>
<div class="product-text">
<h2 class="product-title"> <%= product.name %></h2>
<h3 class="product-price">£<%= product.price %></h3>
</div>
<% end %>
<% end %>
</div>
You can do this way
in your controller you can write this code
def show
#category = Category.find_by_name(params[:name])
end
and in your view it will work
<div class="grid">
<% #category.products.each do |product|%>
// place your code what you want to display
<% end %>
</div>
I hope it would help you and still if you have any concern please let me know.
I am trying to create a todo app that will allow the user to create lists and then "todo" items under each list. However, I want each user to only be able to see his or her lists. While I've been able to partially solve it using the current_user helper, the index page shows empty space where the other users lists are hidden.
Below please find the code for the index.html.erb page inside my todo_lists views.
<% #todo_lists.each do |todo_list| %>
<div class="index_row clearfix">
<% if todo_list.user == current_user %>
<h2 class="todo_list_title"><%= link_to todo_list.title, todo_list %></h2>
<p class="todo_list_sub_title"><%= todo_list.description %></p>
<p><%= todo_list.user.first_name %></p>
<% end %>
</div>
<% end %>
<div class="links">
<%= link_to "New Todo List", new_todo_list_path %>
</div>
Here's my repo on Github, in case you need to see more of the code: https://github.com/jramoscolon/todo
Is there a way to hide these empty spaces, as well as the non-matching todo items?
Given your current view code, you are indiscriminately emitting <div class="index_row clearfix"> elements, even when the todo_list.user does not match the current_user. Simply move the whole<div> outside the current_user check, like so:
<% #todo_lists.each do |todo_list| %>
<% if todo_list.user == current_user %>
<div class="index_row clearfix">
<h2 class="todo_list_title"><%= link_to todo_list.title, todo_list %></h2>
<p class="todo_list_sub_title"><%= todo_list.description %></p>
<p><%= todo_list.user.first_name %></p>
</div>
<% end %>
<% end %>
This way, all of those empty <div> elements aren't included on the page. This should clean up all that empty space.
If your index view is user specific than the instance variable you want should be user specific as well.
Instead of #todo_lists = ToDoList.all
Use the current_user.todo_lists functionality supplied by your has_many/belongs to
How to make this code work?
<%= articles= Article.find_each
if articles
a.each do |a| %>
****some html****
<% end %>
<% end %>
right now it gives me an error:
no block given (yield)
It's hard to tell because your code is such a mess but i think you are trying to do this:
<% Article.all.each do |article| %>
<!-- some html - reference the local variable `article` in here, inside erb tags, eg -->
<div>
<%= article.name %>
</div>
<% end %>
EDIT: the above code will work fine (by which i mean happily generate no html at all) if there are no Article records in the db. Sometimes in this situation you might want to display some sort of extra info, like "You haven't created any Articles yet" or something. if this is the case you could do something like this:
<!-- typically this variable would be defined in the controller -->
<% #articles = Article.all %>
<% if #articles.blank? %>
<p>You haven't created any Articles yet</p>
<% else %>
<% Article.all.each do |article| %>
<!-- some html - reference the local variable `article` in here, inside erb tags, eg -->
<div>
<%= article.name %>
</div>
<% end %>
<% end %>