I have two Models User and Site. The User has category like 'basic and premium'. The user has relation to sites one -> many (i.e one user can have more than one sites). Now i want to select sites of premium user. Can someone tell me how to use where clause in ActiveRecord to achieve this?
I want to select sites of premium user
This will do
User.includes(:sites).where('users.category = ?', 'premium')
Update
If sites also have categories like 'wordpress or joomla', how do i
apply where clause to select only wordpress sites of premium users
For that you need to tweak the query like this
User.includes(:sites).where('users.category = ? and sites.category = ?', 'premium','wordpress')
As you said that category is a column, so Rails automatically generates the following method for you:
User.find_by_category("basic")
If you do not want to use this, you can use where method, in which you have to send a key-value pair like following:
User.where(:category => "basic")
And when you have found a user with the category you desired, you can simply call sites on it to get all the associated sites with a particular user.
You can try this also:
#user_ids = User.where(category: 'premium').pluck(:id)
#sites = Site.where(user_id: #user_ids)
Related
I'm new to RoR and I need a query that returns the same instances as the following definition of queue :
#all = User.all
#membersOfActivity = User.where(id: User.joins(:memberships).where("activity_id = ?", session[:current_activity_id]))
#usersIAlreadyLiked = User.where(id: User.joins(:likes).where("activity_id = ? AND activity_likes_user IS NOT NULL", session[:current_activity_id]))
#notWanted = #membersOfActivity + #usersIAlreadyLiked
#queue = #all - #notWanted
However, I understand how inefficient the query I just wrote is for it downloads all the Users first to then select the complement. Do you have any idea on how to make it more efficient and directly select the complement of #notWanted? I tried several queries but none of those worked.
If you think you have a better solutions please let me know! Thanks!
EDIT :
Each user has many memberships, that connect a user with an activity. So each activity has also many membership. Each membership has a user_id and an activity_id.
Each user has many likes, and each like connects a user and an activity. Therefore each activity has also many likes. A like has a user_id, activity_id, user_liked_activity, and activity_liked_user.
user_liked_activity is NULL if the user did not express an opinion about the activity, TRUE is the user liked the activity, and FALSE if the user disliked the activity. Viceversa for activity_liked_user.
Here's a Rails 5 solution, using not syntax. At first glance, this appears to be similar to your original solution, but this runs only one query, built from the separate excludable categories (members and already_liked).
class User < ApplicationRecord
has_many :likes
has_many :memberships
def self.queue(current_activity_id)
members = User.joins(:memberships).where(memberships: {activity_id: current_activity_id})
already_liked = User.joins(:likes).where(likes: {activity_id: current_activity_id, activity_liked_user: [true, false]})
where.not(id: members).where.not(id: already_liked)
end
end
You will call this from your controller like so:
#queue = User.queue(session[:current_activity_id])
As I understand the problem, for the current session activity, we want a query that will return all users except those that belong to one of two categories: (1) Those who are members of the activity, represented by users having a membership linked to the current activity, and (2) those who already have a "liked" rating from the activity, represented by users having a "like" linked to the current activity for which activity_likes_user is either true or false (but not nil).
We establish ActiveRecord relations for each category, but we don't call anything that would actually trigger a query. Category 1 is members, and Category 2 is already_liked.
Now we build a query on the User model (this is implied, because we are calling from within a class method on the User class) asking for users where id is not one of the members and is not one of the already_liked.
There may be a more elegant solution, but this does work, and I believe it handles edge cases properly, though you should build tests to verify this.
I want to do something like Report.last, but instead of the last record entered, I want the last record that a specific user entered.
You are probably looking for something like
Report.where(created_by_id: user_id).last
where the key in the where clause is the foreign key in a reports table record to the association with the user. I'd have to know how your models associate reports with their creators to know the right syntax.
You need to include the user_id or some sort of user indicator to be able to get the last record for a specific user. You will need to post more information like the model for your users and reports. But I think you are looking for something like this:
Report.select([:user_id, :id, 'MAX(created_at)']).group(:user_id).limit(5)
user = User.where(:some_condition => "some_value").first
user.reports.last
This would work if user is a local variable representing an active record user and records would query its associated records and find the last one.
I assume you have model relationship between User & Report
user = User.first
user.reports.order("updated_at DESC").last
Can anyone tell me if it's possible to eager load an association but only return specific attributes?
I'd like to retrieve some orders with their accounts but only require the account names.
Order.select([:id, :account_id]).includes(:account).limit(2)
I think jvnill's comment says it all:
I'm not sure that is possible. You can however add the account_name to the returned order records.
orders = Order.joins(:account).select('orders.id, orders.account_id, accounts.name AS account_name')
then just use account_name like orders.first.account_name
I have a User model, the user can gradually insert information on their profile (age, description, avatar, etc..). Those users can be viewed in the public web site only if they have complete their entire profile.
Whats is the best way in rails to put constraint on query without polluting every single call to Active Record User model. Is there're a way for
User.all
to return result with those constraints by default?
Tks a lot!
You could define a scope.
# user.rb
scope :complete, where("age IS NOT NULL", "description IS NOT NULL",...)
Then you can just do User.complete and it will fetch User objects matching those conditions. For more information:
http://api.rubyonrails.org/classes/ActiveRecord/NamedScope/ClassMethods.html
I'm using ASP.NET MVC 1 and I have added a custom Profile class using the WebProfile Builder VS add-in (found here: http://code.msdn.microsoft.com/WebProfileBuilder/Release/ProjectReleases.aspx?ReleaseId=980).
On one of my forms I want a drop-down list of all users who share a specific profile value in common.
I can see that I can get a list of all users using:
Membership.GetAllUsers()
However I cannot see how to get all users who have a specific profile value, which in my case is CellId.
Am I approaching this in the right way? I have used membership roles to define which users are administrators etc, but profiles seems like the right place to group users.
Any pointers both in specifics of how to access the user list but also comments on whether am I pursuing the right avenue here would be greatly appreciated.
Many thanks,
Sam
There is no query API for Profile, but this may give you some guidance:
var usersWithNonZeroCounter = Membership.GetAllUsers().Cast<MembershipUser>()
.Where(user => true /*insert your user criteria here*/)
.Select(user => ProfileBase.Create(user.UserName, true))
.Where(profile => ((int)profile["counter"]) > 0 /*insert your profile criteria here*/)
.ToList();
If you only need one comparison you can use following statement:
return Membership.GetAllUsers().Cast<MembershipUser>()
.Where(user => ((int)ProfileBase.Create(user.UserName, true)["Owner"]) == _ownerid);
If you need more evaluations, why dont you use the let operator to store the profile in.