I have a model called User which has_one Player. A Player belongs_to a User.
I want to find all the Players which Users attributes City has a particular value. Right now I have this in my Player model:
def find
User.find(:all, :conditions => ['city LIKE ?', "%#{city}%"])
end
However that gives me the User. I want the Players which Users satisfy that condition.
How do I do that?
Try this.
Player.joins(:user).where('user.city LIKE ?', "%#{city}%")
Related
Ruby on Rails app with ActiveRecord and Postgres database. I have this relation of two models with a join table in between, basically every user can like multiple movies:
class Movie
has_many :user_movie_likes
has_many :users, through: :user_movie_likes
end
class UserMovieLike
belongs_to :movie
belongs_to :user
end
class User
has_many :user_movie_likes
has_many :movies, through: :user_movie_likes
end
Considering I have the user id, I can easily fetch all the movies that are liked by this user, something like:
# movie.rb
scope :liked, ->(user_id) { joins(:user_movie_likes).where('user_movie_likes.user_id' => user_id) }
But I can't figure out how to do the inverse of this - all the movies that the given user didn't like yet. If I do where.not('user_movie_likes.user_id' => user_id), it will still return movies that the user liked, because some other user liked them, and will not return movies that have no likes at all. For now I'm just plucking the ids from the liked scope and do where.not(id: liked_ids), but I'm sure there is a good way to do it in one query. I found some other questions similar to this one on StackOverflow, but they were different cases, i.e. finding movies that have no likes etc.
Try the below:
scope :liked, lambda { |user_id|
joins("LEFT OUTER JOIN user_movie_likes ON user_movie_likes.movie_id = movies.id AND user_movie_likes.user_id = #{user_id}")
.where('user_movie_likes.id IS NULL')
}
I'm creating a messaging system. A user can start a conversation by messaging multiple recipients who in turn can reply back.
I want to find all conversations a user is participating in. Ie. conversations where they have either authored a message or were a recipient of a message in the conversation.
Currently my models looks like this
# Message
belongs_to :conversation
belongs_to:user #author
has_many :receipts
has_many :recipients, :through => :receipts
# Conversation
has_many :messages
# User
has_many :receipts
has_many :incoming_messages, through: :receipts, :class => 'Message'
# Receipt
belongs_to :message
belongs_to :user
I want to create a scope on Conversation to achive something like this
Conversation.involving(user)
Not sure how to write the scope / sql for this. It feels like I need the equivalent of an OR statement in there.
ie. in PSEUDO CODE
conversations where (messages.recipient_ids include user.id OR messages.user_id == user.id)
I'm assuming ive modeled the system correctly. If not any better schema suggestions would also be greatly appreciated.
Can anyone help with either.
Something like this should work:
Conversation.includes(messages: :receipts).where(["messages.user_id = :user_id OR receipts.user_id = :user_id", user_id: user.id])
This is doing the where clauses on the user_id foreign keys so that you don't have to figure out what table aliases ActiveRecord would assign to the users table (since it would be joined twice).
I have users and companies in a many to many relationship by a join table which has a column for user Role. I'm not sure if this is the best way to have the model set up.
Now each user can have different roles depending on the company, what is the best way to design and access user's role using ActiveRecord associations?
I would like to return via JSON the user's role based on their current company and default to something if their company is nil OR their role has not been set (nil).
Update:
What I've got now after reading Many-to-many relationship with the same model in rails? which is a bit different (many to many on itself).
CompaniesUser
belongs_to :company
belongs_to :user
Company
has_many(:companies_users, :dependent => :destroy)
has_many :users, :through => :companies_users
User
has_one :company
has_many(:companies_users, :dependent => :destroy)
has_many :companies, :through => :companies_users
Appreciate any advice as I'm just starting to learn this!
What you have above is correct, in terms of the ActiveRecord relationships. If you'd like to read more on the subject I believe this is the best source: http://guides.rubyonrails.org/association_basics.html
One problem I see there is that CompaniesUsers should be in singular form: CompanyUser, and then in all cases where you use :companies_users use: :company_users
I am assuming here that the current company of the User is the last one assigned.
Now in order to serialize in JSON format you should add the following in your User ActiveRecord:
def serializable_hash(options = nil)
options ||= {}
h = super(options)
if(defined?self.company_users.last and defined?(self.company_users.last).role)
h[:role] = (self.company_users.last).role
else
h[:role] = 'default_value'
end
end
I am trying to allow users to search through their own friends by email address. I'd like to do something like:
current_user.search('test#fake.com')
and have it return an array of current users friends that have that email address.
So I have a very basic friendship relationship set up on my user model
user.rb
has_many :friendships
has_many :friends, through: :friendships, source: :friend
has_many :inverse_friendships, class_name: 'Friendship', foreign_key: 'friend_id'
has_many :inverse_friends, through: :inverse_friendships, source: :user
friendship.rb
belongs_to :friend, class_name: 'User', foreign_key: 'friend_id'
belongs_to :user
I want to set up a method on my user model that can search through their friends by email address. It's not working so well
def search(query)
conditions = ['friends.user_id = ? AND email LIKE ? ', self.id, "%#{query}%"]
User.includes(:friends).where(conditions)
end
I guess I'm just not sure how to format my active record query / SQL here, since I am trying to search on the relations of a self referential model. Any one have any ideas?
Thanks!
Digital Cake is going in the right direction, but not exactly correct. A scope is a method of User, not user. What you need is:
def followers_by_email(email)
friends.where("email like ?", "%#{email}%")
end
This returns an ActiveRecord::Relation to which you can chain other conditions, order, paginate, etc as in
user.followers_by_email("me#example.com").order(:first_name).limit(10)
Good time to use active record scopes. http://guides.rubyonrails.org/active_record_querying.html#scopes
Heres a simple example
user.rb
scope :followers, friends.where(:published => true).order("created_at DESC").limit(150)
in your controller
#followers = User.followers
I seem to have some success with:
conditions = ['contacts.user_id = ? AND users.email LIKE ? ', self.id, "%#{query}%"]
User.includes(:inverse_friends).where(conditions)
Though it's strange that it works, I'm not entirely sure why it does.
Hi: I'm struggling with a rails query. Finally, I want to make a JSON response with the following contents: A listing of all countries which have at least one company, associated through "Address" and a count of how of how many companies reside in a country.
Here is my simple model structure:
class Country < ActiveRecord::Base
has_many :addresses
end
class Address < ActiveRecord::Base
belongs_to :country
belongs_to :company
end
class Company < ActiveRecord::Base
has_one :address
end
What's the most elegant way to solve this with Rails?
You need to overload the to_json method :
class Country < ActiveRecord::Base
has_many :addresses
def to_json
# format your country as json with all the elements you need
end
end
Then in your controller do something like that:
countries = Country.find(:all).select{|c| c.companies.size > 0 }
json = countries.collect{|c| c.to_json }
You'll have to use has_many throught to get the companies from a country. Documentation here: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
Sorry I don't have time for a more precise solution, but hopefully these pointers will help you. If you have specific problems, feel free to either comment or open a new question.
You might want to add a counter cache to Address
belongs_to :country, :counter_cache => :companies_count
It stores the number of companies in the country model, which saves you from the N+1 query issue.
Alternatively you could avoid it also by issuing a single query like this:
Country.find(:all, :select => 'countries.*, count(addresses.id) as companies_count', :joins => 'LEFT JOIN addresses ON addresses.country_id = countries.id', :group => 'countries.id')
This way all of the returned countries will have field companies_count containing the number of companies for that country.