Rails - Find with no associated records - ruby-on-rails

I want to select one user and add to it associated records such as child for this example.
But only the child with a specific place_id.
This code works, but when the user doesn't have any child entry I got an error.
#user = User.includes(:child).find(params[:id],
:conditions => ["child.place_id = ?", #place_id])
Here is the error:
Couldn't find User with id=19 [WHERE (child.place_id = 0)]
Thanks !

Try where clause, since you are already using brute SQL. This will not produce error and will either fetch or set to nil:
#user = User.includes(:child).
where("users.id=? AND child.place_id = ?",
params[:id],#place_id).first
PS: Is it child.place_id or children.place_id? ActiveRecord tends to pluralize table names.
EDIT:
This only works if there are children. If you want it to work event without children,do this:
#user = User.joins('LEFT JOIN child on child.user_id = users.id').
where('child.place_id = ? AND users.id = ?', #place_id, params[:id]).
select('users.field1, child.field2 as field3')
If you want specific fields, add them in select method above, which is provided as an example.

Related

How to Sort Record in Ruby on Rails based on Last Record Timestamp from References Table

I need to create a live chat app and now I have three models :
ChatRoom
ChatRoomMember
ChatRoomMessage
From this three models, I use includes and references to get the list of chat_rooms for current login user. Here is the code that I have wrote.
#chat_rooms = ChatRoom.includes(:members).references(:members)
#chat_rooms = #chat_rooms.includes(:messages).references(:messages)
#chat_rooms = #chat_rooms.where 'chat_room_members.user_id = ?', #current_user.id
#chat_rooms = #chat_rooms.order 'chat_room_messages.created_at DESC'
#chat_rooms = #chat_rooms.limit(limit).offset(offset)
However, the order didn't work as I expected. What I want is that the chat_rooms are sorted by created_at column from the last message in that room. How can I do this ?
Here is the database structure :
Use association to avoid where 'chat_room_members.user_id = ?', #current_user.id
Here is my suggestion, assuming User has associations looking like:
class User
has_many :chat_room_members
has_many :chat_rooms, through: :chat_room_members
end
# list only rooms with at least on message
#chat_rooms = #current_user.chat_rooms.joins(:messages).order('chat_room_messages.created_at DESC').limit(limit).offset(offset)
# list all rooms even if there is no message attached
#chat_rooms = #current_user.chat_rooms.distinct.left_joins(:messages).order('chat_room_messages.created_at DESC').limit(limit).offset(offset)
Try this:
ChatRoom.includes(:messages).order('chat_room_messages.created_at DESC')
Thanks for everyone has help me to solve this probel. I have my own answer. Here is it.
SELECT chat_rooms.*, (SELECT chat_room_messages.created_at FROM chat_room_messages WHERE chat_room_messages.chat_room_id = chat_rooms.id ORDER BY chat_room_messages.id DESC LIMIT 1) AS last_message_at FROM chat_rooms INNER JOIN chat_room_members ON chat_room_members.chat_room_id = chat_rooms.id WHERE chat_room_members.user_id = #{#current_user.id} ORDER BY last_message_at DESC
I use raw query for solve this problem. Hope this can help anyone who need it !

Rails query to retrieve related association for all query

Beginner # rails here.. When using find_by_id I can retrieve the associated record but I'm unclear on how to do this through the all query. How can I adapt the find_by_id LEFT..JOIN for .all so it also retrieves the associated model.
My fail
#user = User.all.joins(:userpaintings).joins("LEFT JOIN paintings on userpaintings.painting_id = paintings.id")
This works
#user = User.find_by_id(1).joins(:userpaintings).joins("LEFT JOIN paintings on userpaintings.painting_id = paintings.id")
Try this:
#user = User.joins(:userpaintings).joins("LEFT JOIN paintings on userpaintings.painting_id = paintings.id").all
#all will convert the relation into an Array, which you can't run methods such as #joins on.

rails getting attributes of associated model for many objects in one query

My title might be confusing, I wasn't sure what to write.
In rails I understand how to fetch Many Objects for One parent object
#first_user = User.first
#first_user_posts = #first_user.posts
But how can I fetch Many Objects for Many parent objects and select its attributes in one query?. I am trying to do something like that:
#many_posts = Post.all
#posts_by_user_gender = #many_posts.joins(:user).map(&:gender)
hoping it would give me an array that could look something like this:
#posts_by_user_gender => ["male", nil, "female", nil]
#I know I can do this map technique if I fetch it directly from the User model
# User.all.map(&:gender),
# but I want to start with those that posted in a specific category
# Post.where(:category_id => 1)
and then to count the males I could use the Ruby Array method .count
#males_count_who_posted = #posts_by_user_gender.count("male")
=> 1
I could always do 3 separate queries
#males_count_who_posted = #many_posts.select(:user_id).joins(:user)
.where("gender = ?", "male").count
#females_count_who_posted = ...
but I find that extremely inefficient, especially if I do the same for something like "industry" where you could have more than 3 options.
you can join model via SQL syntax
#posts_by_user_gender = #many_posts.joins("LEFT JOIN Users where users.id=posts.user_id").joins("LEFT JOIN Genders where genders.id=user.gender_id")

Why does ActiveRecord query return ambiguous column reference?

In a Rails app I'm setting up nested routes
resource Country do
resource State
resource City
resource User
resource Post
end
I now want to display users that have posted within a country at ../country/1/users
In the User controller I have:
def index
#user = User.includes(:posts, :city, :state, :country)
#user = #users.where("states.country_id = ?", params[:country_id]) if params[:country_id]
#active_users = #users.where('posts_count > ?', 0).ranked_scope
end
I'm, getting:
PG::Error: ERROR: column reference "posts_count" is ambiguous
LINE 1: ...untry_id" WHERE (states.country_id = '1') AND (posts_co...
I'm not sure if this is because:
There is a posts_count column on User, City, State, Country models and the query does not know which on to use. If so, what is the correct syntax to specify the table?
I'm stringing together two where clauses incorrectly.
Something else....?
I'd appreciate any suggestions or ideas.
Try:
#active_users = #users.where('users.posts_count > ?', 0).ranked_scope
OK, I eventually got to the bottom of this. The following query was incorrect
#users = #users.where("states.country_id = ?", params[:country_id]) if params[:country_id]
Post belongs to User, and Post has one Country through State. Without a direct relationship in one direction between USer and Country, I modified the query to
#users = #users.where(id: Country.find(params[:country_id]).users.uniq if params[:country_id]
(and double checked all my model relationships were properly configured).
Works!
The error message was not very helpful in tracking this down though!

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