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
Related
I am trying to make it possible for an unregistered user to shop.
I use cookies for this.
For the cart view I use:
in controller: #cart_items = cookies[:cart_items].split(',')
in view:
<% #cart_items.each do |cart_item| %>
<%= Product.find(cart_item).title %>
<%= Product.find(cart_item).price %>
<% end %>
but i think it's not so good.
What is the best way to find all products by id array?
in controller do this so you are preparing the queried one in the view
controller:
#cart_items = Product.where(:id => cookies[:cart_items].split(','))
and in the view you do this
<% #cart_items.each do |cart_item| %>
<%= cart_item.title %>
<%= cart_item.price %>
<% end %>
Cookie parsing definitely does not belong in the view. And you should also generally avoid querying the database in the view. The view should ideally just take data from the controller and display it.
Also never use .find in a loop. It will create a database query for each iteration. It will also raise a ActiveRecord::RecordNotFound exception if any of the ids where not found in the database.
So:
#cart_items = Product.where(id: cookies[:cart_items].split(','))
Is less bad. But hardly ideal as it won't let you handle quantities. Instead you could store JSON or create a "guest" Cart record in the database.
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).
I've set up a my site so that my users can create individual product collections and add their listings to each collection. I then created a site page that shows all created collections by all users. Right now I have the collection name and the "by so-and-so" displaying there for each collection, all good. I now want to show the first 3 listing images for each collection on top. I am able to get the first 3 images from my listings database to show in each collection using #listings = Listings.all, but that's not correct. But at least that confirms everything connects. I'm having trouble with my controller to def the #listings by 'collection_id'. I've tried so many different variations and the one below is where I'm currently stuck and serves a blank collection and doesn't recognize any/or each collection's listings.
My Pages Controller:
#collections = Collection.all.order("created_at DESC")
#listings = Listing.where(collection_id: #collection)
My Collections View Page:
<% #collections.each do |collection| %>
<% #listings.limit(3).each do |listing| %>
<%= image_tag listing.image.url(:small) %>
<% end %>
<%= collection.name %>
<%= collection.user.business_name %>
<% end %>
What am I missing in my controller to get the images to show by :collection_id? Do I need to change anything in my view page? Additionally, is it okay to nest the #listings.limit(3).each within my #collections?
The listing you are querying is not related to the collection, you should do something like this instead
<% #collections.each do |collection| %>
<% collection.listings.limit(3).each do |listing| %>
So you don't need a #listings query, but what you need instead is eager loading so you don't keep querying in each loop
#collections = Collection.includes(:listings).order(created_at: :desc)
If images are another object too, then you could include them in the includes too
#collections = Collection.includes(listings: :images).order(created_at: :desc)
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 have a model that have a column for name and a column for categories. There are a large amount of names that I would like to list by category but I haven't figured out how to do it.
Currently in the view I have
<% for car in #cars %>
<%= car.name %>
<% end %>
which just presents this huge list of that is way too unwieldy. I'm using #car = Car.find(:all) in the controller to get the selection.
=> If there a way I can create some form of dynamic table where it groups all the car records by category and makes a new column for each category instance, with a listing of all the associated cars?
=> I'm also afraid that that might be too many columns so after 5 or so columns can I start a new row?
=> Should I do all this in the controller or the view?
Can you specify some sample values for the category column?
Depending on what you have stored you may be able to do this:
Car.find(:all).group_by(&:category)
Which will put the cars into an ordered hash indexed by the different category values.
<% #car_categories.sort.each do |category, cars| %>
<h3><%= category %></h3>
<% for cart in cars %>
<p><%= interest.name %></p>
<% end %>
<% end %>