In my view I'm generating a a number of restaurant menus that are divided into menu categories and within those categories are dishes. Right now I have my template setup as so:
<% #menus.each do |menu| %>
<h2><%= menu.name %></h2>
...
<% menu.categories.each do |category| %>
<h3><%= category.name %></h3>
...
<% category.dishes.each do |dish| %>
<p><%= dish.name %></p>
...
<% end %>
<% end %>
<% end %>
I was wondering what would be best practice when it comes to nesting multiple enumerables in this fashion? Aside from inserting this code into a partial, is there a better way to accomplish this without cluttering the view. Is it fine as is? Thanks.
Apparently, the way your models are setup (Menu has_many categories, Category has_many dishes etc.), if you are to show all those information in the same view, you have no other way rather than just looping through them and show the required data in your view which is fine, IMHO. I don't see any problem with that.
Just one tip, while looping through the associated model's data, you just need to be careful that you always have the data present for the associated model attributes, otherwise you may get undefined method 'method_name' for nil:NilClass error for some of them. To avoid that problem, you can also use try. e.g.
menu.try(:name)
category.try(:name)
dish.try(:name)
etc.
That way, your view will not explode if some or any one of the associated model has no data present (i.e. nil).
Related
Lets say my app has 3 main types of objects the user interacts with: pictures, videos, and "tweets". I have no problem rendering a collection of any one object type or even all three as separate lists:
<% #pictures.each do |picture| %>
<%= picture.name %>
<%= img_tag(picture.url) %>
<% end %>
<% #tweets.each do |tweet| %>
<%= tweet.message %>
<% end %>
<% #videos.each do |video| %>
<%= video.title %>
<%= video.thumbnail %>
<% end %>
What I would like to do is render a single "feed" that consists of all three different object types intermixed in chronological order.
Possible Solutions:
I've seen solutions such as creating an entirely new db table called something like "activity_feed" that has a polymorphic association to all other models and records an entry for every object added to the db. This seems inefficient and overkill for what I'm trying to accomplish. Theres also the "public_activity" gem, which does the same thing.
I've been messing with querying each collection individually, then combining the collections and sorting in ruby, but am having trouble sorting active record objects.
#feed_items = #pictures + #videos + #tweets
Ideally I'd like to be able to query and sort this all from the db layer for performance reasons. (I'm using Postgres!)
I'm new to rails and coding in general. Any help would be greatly appreciated!
You want to make an activity_feed model and then add items to the activity feed model and then query and display the activity feed model versus querying multiple models. Then you can sort on this anyway you want.
def create
if #comment.save
ActivityFeed.create(...)
end
end
Then when you want to display the feed just display it.
https://robots.thoughtbot.com/using-polymorphism-to-make-a-better-activity-feed-in-rails
There are activity feed gems that help with this if you don't want to make it from scratch.
https://github.com/pokonski/public_activity
https://github.com/GetStream/stream-rails
I have a #minisets model and a #miniatures model. They both have_many of each other through the #contents model.
As well as the foreign keys, the #contents model also has a quantity column.
From my #minisets show view I can show the associated #miniatures with the following:
<% #miniset.miniatures.each do |miniature| %>
<%= link_to miniature.name, miniature %>
<% end %>
I want to be able to show the quantity entered for those miniatures but can't work out how to call information from the join table rather than the table it is joining.
Something like <%= miniature.content.quantity %> except that won't work. I assume the joining model must be in play for it to be supplying the joined info but how do I interact with it itself in that instance?
Figured it out.
I need to be working with the join object in the instance variable rather than the joined object.
Find the #contents which belong to this #miniset and then get the #miniature info from there. Makes much more sense.
<% #miniset.contents.where(miniset_id: #miniset).each do |content| %>
<%= link_to content.miniature.name, content.miniature %>
x<%= content.quantity %>
<% end %>
Found some very complicated answers to similar questions but this is dead simple. Hope it helps someone.
I think I am deeply misunderstanding how to write instances.
Miniatures have_many Manufacturers through the Productions table.
On the miniatures show page I am trying to list all the manufacturers for the current miniature and have them link the Manufacturer show page. Like so:
<% #miniature.manufacturers.each do |manufacturer| %>
<%= link_to #miniature.manufacturer.name, manufacturer_path %>
<% end %>
Needless to say it does not work. It gives "undefined method `manufacturer'".
I have tried A LOT of different combinations to no avail. The following version puts all the manufacturers, rolled into one link, once for each manufacturer a miniature has, and links to /manufacturers. A big mess.
<% #miniature.manufacturers.each do |manufacturer| %>
<%= link_to #miniature.manufacturers.map(&:name).join(', '), manufacturer_path %>
<% end %>
I have been working on other things and hoping I would get the hang of this but I'm pretty sure it's something pretty fundamental about how I set up the instance.
If it's more likely something I need to add to the controller then I can add my controller code here. Any help much appreciated.
Does this work:
<% #miniature.manufacturers.each do |manufacturer| %>
<%= link_to manufacturer.name, manufacturer_path(manufacturer) %>
<% end %>
I am building a simple app and in many views I am displaying all of the objects associated with a certain model (many-to-one relationship). For example, I have a house model and an Item model where House has many Items. On the Show view for house I have the following code:
<% #house.items.each do |item| %>
<% if item.needed == true%>
<p>
<%= item.description %>
</p>
<% end %>
<% end %>
and this displays all the items along with one blank item. If I delete all the items, leaving an empty array there is still one empty item remaining. I can hack this using the code:
<% #house.items[0..-2].each do |item| %>
<% if item.needed == true%>
<p>
<%= item.description %>
</p>
<% end %>
<% end %>
This is probably a really simple question, but I would like to avoid using the latter code, and would like to understand why this is happening. Thanks.
The issue you are seeing is data related. This is to say, you need to figure out what is being returned by #house.items. Perhaps you have an item that has needed == true and a blank description? To trouble shoot this verify what is being returned by the house object in question by opening up the rails console, loading the house object in question and checking what is returned by house.items.
When using #house.items.new to set up a new Item object, it will alter the #house.items array, even though the new item is not yet persisted to the database. Example:
items = #house.items
items.length
# => 3
item = #house.items.new
items.length
# => 4
You could either add a check inside your loop for something like if item.persisted? or unless item.new_record?. Or, you could build the new item this way instead, which won't include it in #house.items until it's actually saved to the database:
item = Item.new(house_id: #house.id, needed: true)
I'm wondering if theres a best practice for what I'm trying to accomplish...
First we have the model categories, categories, has_many posts.
Now lets say, users add posts.
Now, I have a page, that I want to display only the current user's posts by category.
Lets say we have the following categories: A, B, and C
User 1, has posted in Categories A and B.
In my view I have something like:
#categories.each do |category|
category.name
#posts.each do |post|
if post.category_id==category.id
post content here
end
end
end
The problem with this, is I'm going to show the empty category, as well as the categories that do have content.
Is there a more efficient way of going about this? As I don't want to show the empty categories.
Best,
Elliot
UPDATE:
So I've been trying to use this code:
0}.each do |category| %>
For the most part its almost there. The issue is, it will still show an empty category if any posts have been entered in it at all (even if the current user has not input posts into that category.
So the question boils down to:
How do I make the following loop only count posts in the category from the current user?
0}.each do |category| %>
<% #categories.select {|cat| cat.posts.count > 0}.each do |category| %>
<%= category.name %><br/>
<% category.posts.select {|post| post.user == current_user}.each do |post| %>
<%= post.content %><br/>
<% end %>
<% end %>
This renders each category with any posts, then the content for each post within the category belonging to the current user. You'd probably want to do the initial selection in the controller though, to keep the view clean.
Adding to zetetic's answer, perhaps the lookup of the posts of a user in a given category would be done the opposite way. Instead of querying "All the posts for the category where the author is the current user", ask for "all the posts for the user where it is in given category"
<% #categories.select {|cat| cat.posts.count > 0}.each do |category| %>
<%= category.name %><br/>
<% current_user.posts_in_category(category).each do |post| %>
<%= post.content %><br/>
<% end %>
<% end %>
And throw a scoped search User#posts_in_category
EDIT: Probably you should also set the #categories variable already filtered from your controller, if you're not showing them somewhere else in your view. Also, if the category has no posts, it will not enter the cycle, so maybe the select is not needed.
#categories.select do |category|
category.posts.any? {|post| post.user == current_user }
end
Will filter out the categories to have only categories with posts by the current_user. I guess it would be more efficient doing this in the db, use this if you're fetching the #categories anyway.
As per my concern you need to have an intermediate table for users who publish posts for a given category that table might have following fields
user_id,post_id, category_id by this way you will be having a table which has category id's and for each category there is a post.
then you can do the following
get the distinct categories (from above table)
loop through the categories
get posts for those categories
** then you will not get any categories without posts
cheers,
sameera