Get array of fields from a belongs_to association? - ruby-on-rails

I have a object User and object Post. A User has_many Posts and a Post belongs_to a User.
I can access the posts a user has using syntax like:
posts = #user.posts
However, I want to generate an array of ids of the posts a user owns, without looping through each one. Ideally, I'd like to do this:
ids = #user.posts.id
However, I get an error, saying that id is an invalid method for ActiveRecord--etc etc...
Is there any way to neatly do this without having to do a loop like:
ids = []
posts = #user.posts
posts.each |post| do
ids << post.id
end

Rails provides a native method for this:
#user.post_ids
Essentially, you can refer to the ids of a has_many association using <singular association name>_idspattern.

Try with ids = posts.map(&:id) or ids = posts.map{|p| p.id }
You can also try with ids = posts.pluck(:id)

You Can also use collect.
Collect returns the Array.
ids = #user.posts.collect(&:id)

try this :
#ids = #user.posts.map{|x| x.id }
Hope it will help.

Related

Find records related to other records in controller (ruby on rails)

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.

Is there a simpler way to return a belongs_to relation of an ActiveRecord result set?

I have two models:
Answers:
belongs_to: user
User:
has_many: answers
Is there a way in Ruby or Rails to do the following in one go instead of creating an array and pushing the needed object into it?
def top_experts
answers = Answer.where(some constraints)
users = []
answers.each do |answer|
users << answer.user
end
users
end
You can user joins
def top_experts
Answer.where(some constraints).includes(:user).collect{|x| x.user}
# Will return an Array of users
end
EDIT:
Use includes for eager loading. It will reduce the no of queries executed to get user.
Hi you can use a select clause to select what should be returned along with the where clause
Vote.select(user_id).where(some contraints)
Use sub-query to get users:
User.where( :id => Answer.where(some constraints).select(:user_id) )
Refer: subqueries in activerecord

Iterating through an activerecord::relation array

How can I iterate through an array of Activerecord::Relation objects? For instance, let's say I have a Comment class and a User class and I'd like to get all the comment contents from 3 specific users (assuming comments belong to users and user_id is the foreign key):
>> #males = Comment.where('user_id IN (?)', ["123","456","789"])
=> [...] #Array of comment Activerecord::Relation objects
Now I'd like to iterate through comments_from_males and collect all the content attribute contents for each comment in the array.
To clarify, the following works but only for the first male returned, but I need all the comments for all males:
>> #males.first.comments.map(&:content)
=> ["first comment", "second comment"]
comments = #males.map {|user| user.comments.map(&:content)}.flatten
Comment.where('user_id IN (?)', ["123","456","789"]).pluck(:content)
The method pluck
You can use
comments_from_males = #males.collect{|e| e.content if e.gender == "male"}.flatten
It will give you list of all comments from males. Check my db assumptions match.

ActiveRecord query returns an incorrect model

I have been scratching my head over this one for a little while, and though I'm sure its a stupid mistake, I've reached the point where I must consult SO if I am to preserve the hair follicles I have left.
I've written a function in Rails (3.1.2) which should return an array populated with ActiveRecord model objects (users, in this case) which meet a certain criterion. The criterion is that the user's current list (denoted by the field active_list_id) must not be nil. The code follows:
def build_list_array
#lists = Array.new
User.all.each do |user|
#active_list_id = user.active_list_id
#lists<< List.find(#active_list_id) if #active_list_id != nil #TODO WHAT?!? WHY IS THIS RETURNING USERS?
end
end
As you can see, I'm initializing an empty array, cycling through all users and adding their active list to the array if the relevant reference on the user record is not nil. The problem is, this is returning user objects, not list objects.
Here are the associations from the user and list models:
user model:
has_many :lists
has_many :tasks
list model:
belongs_to :user
A brief word about the reference to active_list: A user can have many lists, but only one is active at any time. Therefore, I need to reference that list on the user record. The active list is not a foreign key in the typical sense, then.
I appreciate any help you can give me...Thanks =)
As it stands, your build_list_array will return an array of User because of the behavior of each. When iterating over a collection using each, the call to each returns the original collection.
For example,
list = []
# returns => []
[1,2,3,4,5].each { |number| list << number * 10 }
# returns => [1, 2, 3, 4, 5]
list
# returns => [10, 20, 30, 40, 50]
In your code, the last statement in your build_list_array method is the each call, meaning the return value of each is what is returned by the method. If you simply added a return statement at the end of the method you would be good to go.
def build_list_array
#lists = Array.new
User.all.each do |user|
#active_list_id = user.active_list_id
#lists<< List.find(#active_list_id) if #active_list_id
end
return #lists # Actually return #lists
end
That being said, you should probably use something like Bradley's answer as a basis for more "correct" Rails code.
each always returns the collection it iterates on (no matter what happens inside the block). Sounds like you want to return #lists at the end of your method.
You seem to be making a curious use of instance variables. You could also fetch this in one query via a join, something along the lines of
List.joins('inner join users on active_list_id =lists.id')
Activerecord's Arel is your friend here:
User.where(:active_list_id.not_eq => nil)
Extending Steven's answer, to get the Lists
class User
belongs_to :active_list, :class_name => "List"
def build_list_array
#lists = User.where('active_list_id is not null').map(&:active_list).compact

rails where() sql query on array

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.

Resources