A clean way to update attributes across objects? - ruby-on-rails

I want to do something like this:
Given:
#user1
#user2
Where the Post model has (id, user_id)
#posts = #user1.posts
I want to take all of the posts of user1, and set the user_id to #user2
Is there an easy one liner way to do this? Or do I have to loop through all the #posts and update attributes and save the record?
Thanks

You can use the class method update_all on your Post class to accomplish this. The first string passed is essentially the SET clause of an SQL update statement, the second string is the WHERE clause.
Post.update_all("user_id = #{#user2.id}", "user_id = #{#user1.id}")

I use the _ids attribute for this.
#user2.update_attribute(:post_ids, #user1.post_ids)
More explanation
If you type
#user1.post_ids # --> [1,2,3,4]
You will get all the ids for all the posts the user is connected to in an array.
You can also set the relationship in this way too
#user2.post_ids = [1,2]
#user2.save
So, to solve what you are asking about I simply assigned the array of post ids of #user1 to the post ids for #user2.

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.

Ruby Gem ActiveRecord find method with multiple conditions

I'm building a Sinatra application using three database's tables: user, post and like.
I'd want to run a query that will find an entry in the like table like so:
FIND in like WHERE user_id == params[:user_id] AND post_id == params[:post_id]
(for one condition I'll be using: Like.find_by_user_id(params[:user_id]))
My question is:
How to run a find query with multiple conditions using the ActiveRecord Gem?
Use where:
Like.where('user_id = ? AND post_id = ?', params[:user_id], params[:post_id])
or
Like.where('user_id = :user_id AND post_id = :post_id', params)
Is important to keep in mind that the paremeters of the where need to be converted to the expected type for example params[:post_id].to_i
Similar to find_by_user_id for user_id column you can combine multiple column names and get a dynamic finder find_by_user_id_and_post_id:
Like.find_by_user_id_and_post_id(params[:user_id], params[:post_id])
When there are more than "bearable" columns in the find_by_ finder, you could use where and supply the condition as follows:
Like.where(user_id: params[:user_id], post_id: params[:post_id])
Like.find_by_user_id(params[:user_id]) - this syntax is deprecated in ActiveRecord 4.
Instead try using where method of ActiveRecord query interface, to pass array conditions. Example:
Like.where("user_id = ? AND post_id = ?", params[:user_id], params[:post_id])
If you are expecting one record to be the result:
To replace find_by_whatever you can use find_by(whatever) for example User.find_by(username:"UsernameIsMyUsername",password:"Mypassword"). You should use find_by if there is only one record that you expect to match your search.
If you are expecting more than one record to be the result:
If you expect more than one you should use where with where(username:"MyUsername",password:"Password"). This will return all the resulting records in an array.

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.

How can I add a virtual "count" column to a select query in rails?

I have a post model, and post has_many :comments, :as => :commentable (polymorphic). I am looking for a way that I can fetch all posts, and have a virtual attribute on the record which will display how many comments belong to that post.
I was thinking that I could just do:
Post.select("posts.*, count(comments.id) as post_comments").joins(:comments)
However, that returns only one record, with post_comments set to ALL comments in the entire database, not just those belonging to the record...
Actually, what you are missing is a group clause. You need to group by site, otherwise the count() aggregation collapses everything to one record as you see.
Try this:
Post.select("posts.*, count(comments.id) as post_comments")
.joins(:comments)
.group('posts.id')
I think the problem is that your count(comments.id) just does one count for the entire joined table. You can get around this with a nested query:
Post.select("posts.*, (SELECT count(comments.id) FROM comments WHERE comments.post_id=posts.id) AS post_comments")
You don't need the join in this case, since the comments table is not used in the outer query.
I would do that with variables in Post model. 1st I would try to find the post I am looking for somehow (you can find it by wichever parameter you want,below I show the example with searching the id param).
#post = Post.find(params[:id])
When you find the post you were looking for, finding out comment number is preety easy, try something along the lines of...
#comments = #post.comments.size
...wich would return an integer.

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