Is there any way of getting all objects, included in Active Relation query?
Something like this:
def index
#items = Item.all.includes(:comments)
#comments = #items.comments // No such method for AR Collection :(
end
The obvious way to get all the items in this case is:
#comments = #items.map(&:comments).flatten.uniq
Thanks to using .includes(:comments) there should be no N+1 queries, but I worry about the performance of this code. Are there any built-in or more effective ways of getting all included records of collection?
You can request comments like this:
#comments = Comment.where(item_id: Item.pluck(:id))
Related
I'm grabbing a list of users and storing in #users.
Now I need to find properties related to only this list of users I have queried.
if params[:company].present?
#users = User.where(parent_id: params[:company]).or(User.where(id: params[:company]))
##properties = #properties.where(user_id: params[:company])
end
I would basically like to include #users inside #properties.where()
I need to get each property that has a user_id present in my #users array
edit:
I just did the following which gives me the result, however, I'm sure there's a much better way of doing this via activerecord:
ids = []
#users.each do |user|
ids.push(user.id)
end
#properties = #properties.where(user_id: ids)
#properties.where(user_id: #users.ids)
That should work. It'll take the id of user ids and perform a filter using the IN clause.
Perhaps adding your models and their relationships we can think about something better.
I have a model Task Orders that has_many Invoices. One of my Task Order attributes is "total invoiced". One of my Invoice attributes is "amount". I want a relationship where Total Invoiced = sum of "Amount". I want this to show up in my task_order/index page. Here is my task order index controller:
def index
#task_orders = TaskOrder.all
#invoices = #task_order.invoices
#task_order.invoicedAmount = #task_order.invoices.sum(:amount)
end
I am getting the error undefined method `invoices' for nil:NilClass
I do want to mention that my code in task_order/show works:
def show
#invoices = #task_order.invoices
#task_order.invoicedAmount = #invoices.sum(:amount)
end
As a follow up question, I am much more familiar with SQL queries than I am using Active Record queries. Can someone point me to a guide on how to render the results of a pure SQL query?
Thank you!!
Your index method is not going to work, because you're getting #invoices from #task_order.invoices, but you declare #task_orders instead. Note the singular vs. plural difference.
I have an array #products. Each element of the array is a hash, containing a few fields (but not all) from Product table and the corresponding values.
I have a scope descend_by_popularity in Product which allows me to sort the products based on popularity field. I'd like to sort the array #products using this scope.
What I tried:
#product_group = Array.new
#products.each do |product|
#product_group.push(Product.find(product['id']))
end
#product_group1 = #product_group.descend_by_popularity
But this gives me error:
undefined method `descend_by_popularity' for #<Array:0xb2497200>
I also want to change the sorted Product list back to the format of #products array.
Thanks
Scopes only make sense within the ActiveRecord context for requests to the database (since it is used to change the SQL query). What you did is throwing a lot of products into an array. This array then knows nothing about the scope anymore. You would have to use the scope when you create the #products object. (and it does not seem to make a lot of sense to move the result of a query into an array)
So something like
#products = Product.descend_by_popularity.where(some more stuff)
should work for you. After that you should have the records in the order defined by the scope and can then either use them directly or still push them into an array if that's what you want to do.
With the updated info from the comments it looks like maybe the best way to go would be to first collect only the Product ids from the solr response into an array and then run that as search together with your scope:
#product_group = #products.map{|product| product.id}
#result = Product.where(id: #product_group).descend_by_popularity
this should technically work, peformance is a different question. I would consider aggregating this data into the Solr document, if it doesn't change too often.
Now assuming you are only interested in the order of products as such, you could do something like this to get #products into this order:
#result.map{|r| #products.find{|p| p[:id] == r.id}
though this may slow down things a bit.
Try this: find_by_id as params
#product_group = Array.new
#products.each do |product|
#product_group.push(Product.find(params['id']))
end
and return the array of #product_group
#product_group1 = #product_group.descend_by_popularity
I have two arrays of objects in ruby on rails. I want to combine them and sort them by two different attributes. Is this possible?
One is an array of 'Post' records, and one is an array of 'Talk' records. They both need to be sorted by date. But for Post, the relevant attribute is created_at while for Talk it's date_given. This is the kind of headache that's making me consider eliminating the two different models and replacing them with a more flexible Post model.
Any thoughts would be appreciated.
I just tried something that worked, but am not sure if it's the best way to handle this issue. I just add a method to each model called sortable date, and set it to what I want. One gotcha with this was that created_at was a Time and date_given was DateTime, so I used this post to deal with that Convert to/from DateTime and Time in Ruby
talk.rb
def sortable_date
date_given
end
post.rb
def sortable_date
created_at.to_datetime
end
Then in my controller -
#posts = Post.order('created_at DESC').limit(3)
#talks = Talk.order('date_given DESC').limit(3)
#news = #posts + #talks
#news.sort_by! &:sortable_date
#news = #news[1..4]
And I just render #news in my view and it summons the appropriate partials nicely. I'd love some feedback.
posts = Post.all
talks = Talk.all
posts+talks.sort do |a,b|
attr_a = a.kind_of?(Post) ? 'created_at' : 'date_given'
attr_b = b.kind_of?(Post) ? 'created_at' : 'date_given'
a.send(attr_a) <=> b.send(attr_b)
end
There should be a SQL way to do this, but well, this way is simpler.
I'll explain this as best as possible. I have a query on user posts:
#selected_posts = Posts.where(:category => "Baseball")
I would like to write the following statement. Here it is in pseudo terms:
User.where(user has a post in #selected_posts)
Keep in mind that I have a many to many relationship setup so post.user is usable.
Any ideas?
/EDIT
#posts_matches = User.includes(#selected_posts).map{ |user|
[user.company_name, user.posts.count, user.username]
}.sort
Basically, I need the above to work so that it uses the users that HAVE posts in selected_posts and not EVERY user we have in our database.
Try this:
user.posts.where("posts.category = ?", "Baseball")
Edit 1:
user.posts.where("posts.id IN (?)", #selected_posts)
Edit 2:
User.select("users.company_name, count(posts.id) userpost_count, user.username").
joins(:posts).
where("posts.id IN (?)", #selected_posts).
order("users.company_name, userpost_count, user.username")
Just use the following:
User.find(#selected_posts.map(&:user_id).uniq)
This takes the user ids from all the selected posts, turns them into an array, and removes any duplicates. Passing an array to user will just find all the users with matching ids. Problem solved.
To combine this with what you showed in your question, you could write:
#posts_matches = User.find(#selected_posts.map(&:user_id).uniq).map{ |user|
[user.company_name, user.posts.size, user.username]
}
Use size to count a relation instead of count because Rails caches the size method and automatically won't look it up more than once. This is better for performance.
Not sure what you were trying to accomplish with Array#sort at the end of your query, but you could always do something like:
#users_with_posts_in_selected = User.find(#selected_posts.map(&:user_id).uniq).order('username DESC')
I don't understand your question but you can pass an array to the where method like this:
where(:id => #selected_posts.map(&:id))
and it will create a SQL query like WHERE id IN (1,2,3,4)
By virtue of your associations your selected posts already have the users:
#selected_posts = Posts.where("posts.category =?", "Baseball")
#users = #selected_posts.collect(&:user);
You'll probably want to remove duplicate users from #users.