Get relation of a collection in rails - sql

So simple but can't find how to do it in rails. I have a specific active record collection of users. Something like users = User.where(blabla). Given this collection is there a simple way to get all posts that those users have? Similar to User.posts, only for all users in that collection.
Post belongs_to User, User has_many posts.
Thanks!

Assuming that your Post model has a user_id with an association called "user", you can do something like this:
Post.where(user_id: User.where(blablah))
or
Post.joins(:user).where(users: {<user conditions>})
You'll need to be able to use the Hash form for the user conditions to use the second option. For example:
Post.joins(:user).where(users: {role: 'member'})
If your users query is more complex, you can create a scope for it:
class User < ApplicationRecord
scope :special, -> { where(< user conditions go here>) }
end
And then merge it with the Post query:
Post.joins(:user).merge(User.special)

Related

Retrieving Records If Their Association Exists in Rails 3.2

I have a User model that has a has_one association with a UserInfo model. I'd like to be able to find all Users that have a UserInfo model. I've tried everything I can think of but nothing seems to work in Rails 3.2:
Users.joins(:user_infos).where("user_info IS NOT NULL")
Users.joins(:user_infos).where("user_infos.id IS NOT NULL")
In each case, I just get back all of the users even though, currently, only 1 of my 1000 users actually has a UserInfo associated with it.
Try this and let me know the response:
in your user.rb write this
def self.available
joins(:user_infos).uniq
end
Joining the user_infos association will remove Users without any user_infos ... SQL is doing your work here.
Now where You want those Users with having user_info, you can get them by using
User.available

Rails Active Record Query for Double Nested Joins with a Select Call

I have the following schema:
Photos has many Groups has many Users.
I am using this Rails server as a backend to an iOS application and constantly need to push out notifications to all involved users of a group when a photo is added.
I problem is finding the least expensive query to resolve only the User.ids affected.
So far I have
Photo.find(1).groups.joins(:users)
I know that I have to put a select argument after this, but can't figure out the syntax for the life of me.
Given a photo, I am looking for the most efficient way to find a collection of the affected user id's.
Any help would be much appreciated!!!
In your Photo model, you can have another associations called users
has_many :group_users, :through => :groups, :source => :users
Then you can find the users by the following code
#photo = Photo.includes([:group_users]).where("photos.id = ?", 1).first
#affected_users = []
#photo.group_users.map {|user| #affected_users << user.id}
Now the #affected_users contains all the user ids.
users_id = []
Group.where(photo_id: 1).users.collect{|u| users_id << u.id}
puts users_id
As Photo has_many groups, so, groups belongs_to photo and groups table has photo_id as foreign key .
So, please try this.

Rails and SQL, how to .last on all members of a table's associations

I am attempting to form the proper query with limited success so far.
Say I have Users and posts
Users has_many posts and posts belongs to user
posts has a visible boolean field
I am trying to write a scope in the user model that goes through all users, finds their last post, and only returns the user if the value if the visible boolean is true on their last post.
Something like Users.posts.last.where(:visible => true) but in as a scope.
EDIT
I'm trying to keep the return value as an AR relation object, a regular array will not work for what I am trying to use the scope for. Thanks though so far for the input.
maybe something like this should work.. (non-tested)
class User
def User.users_with_visible_posts
User.includes(:posts).map {|user| user.posts.last && !!user.posts.last.visible}
end
end
User.users_with_visible_posts #=> [Users with last post visible]
class User < ActiveRecord::Base
has_many :posts
scope :last_visable_post, posts.where("visible = ?",true).last
end

How to test the membership in a many-to-many relation in Rails3

For example, one user has joined many group; and one group has many user members. Now I get a user object and a group object, I want to know whether this user is a member of this group.
I can see some methods, but still wandering whether there is a better way?
So, if i understand your question, what you have is something like:
class User < ActiveRecord::Base
has_many :groups, :though => :user_members
class Group < ActiveRecord::Base
has_many :users, :though => :user_members
And you want to know if a user is a member of a specific group.
So, given something like:
u = User.first
g = Group.first
Just do:
u.groups.include? g
Thats all there is to it!
ian.
ipd's way is fine, another more Rails oriented way to do it is :
u.groups.exists?(g)

Help with Rails find_by queries

Say if #news_writers is an array of records. I then want to use #news_writers to find all news items that are written by all the news writers contained in #news_writers.
So I want something like this (but this is syntactically incorrect):
#news = News.find_all_by_role_id(#news_writers.id)
Note that
class Role < ActiveRecord::Base
has_many :news
end
and
class News < ActiveRecord::Base
belongs_to :role
end
Like ennen, I'm unsure what relationships your models are supposed to have. But in general, you can find all models with a column value from a given set like this:
News.all(:conditions => {:role_id => #news_writers.map(&:id)})
This will create a SQL query with a where condition like:
WHERE role_id IN (1, 10, 13, ...)
where the integers are the ids of the #news_writers.
I'm not sure if I understand you - #news_writers is a collection of Role models? If that assumption is correct, your association appears to be backwards - if these represent authors of news items, shouldn't News belong_to Role (being the author)?
At any rate, I would assume the most direct approach would be to use an iterator over #news_writers, calling on the association for each news_writer (like news_writer.news) in turn and pushing it into a separate variable.
Edit: Daniel Lucraft's suggestion is a much more elegant solution than the above.