Rails ActiveRecord query on existing collection - sql

Suppose I have a result from a query:
allCourses = Course.all
Then I also have another set:
myCourses = current_user.courses.all
How can I get a set of items that are in allCourses and NOT in myCourses?
Here are the models:
class Student < ActiveRecord::Base
has_many :student_enrollments, dependent: :destroy
has_many :courses, through: :student_enrollments
end
class Course < ActiveRecord::Base
has_many :student_enrollments, dependent: :destroy
has_many :students, through: :student_enrollments
end
class StudentEnrollment < ActiveRecord::Base
belongs_to :student
belongs_to :course
end
I can always write raw SQL script to achieve the result, but I prefer to find a Rails way to do it.
Thanks

Assume your fk is user_id.
ohterCourses = Course.where('user_id != ?', current_user.id)

Related

ActiveRocord query with polymorphic associations

I'm trying to get some records from table, but i don't know how to build this query.
I have some models.
class Request < ActiveRecord::Base
has_many :notifications, as: :source
has_many :decisions, dependent: :destroy
end
class Notification < ActiveRecord::Base
belongs_to :source, polymorphic: true
end
class Decision < ActiveRecord::Base
has_many :notifications, as: :source
belongs_to :request
end
So, I need to get all Notifications where source = some_request or source.request = some_request
Isn't it something simple as -
some_request.notifications
# or
some_decision.notifications
and if source is combination of request & decision then
notifications_ids = some_request.notifications.pluck(:id) +
some_decision.notifications.pluck(:id)
Notification.find(notifications_ids)
Your query should be Notification.where(source_id: some_request.id, source_type: 'Request')
Refer Active record association

N + 1 Queries even with Eager loading in Rails 3.2

I have a has_many through, through relationship that needs to be eagerly loaded. Is this possible in Rails 3.2? I've tried several ways to include the association yet calling categories on the facebook_user object always makes another query to Category. Here's a simplified version of my activerecord associations.
class FacebookUser < ActiveRecord::Base
belongs_to :user, touch: true
has_many :user_categories, through: :user
has_many :categories, through: :user_categories
end
class User < ActiveRecord::Base
has_many :user_categories
has_many :categories, through: :user_categories
has_one :facebook_user
end
class UserCategory < ActiveRecord::Base
belongs_to :user
belongs_to :category
end
#single query
FacebookUser.includes( user: :categories).joins(user: :categories).each do |f|
## N+1 query on f.categories
f.categories.first
end
#multi-part query
facebook_user_ids = FacebookUser.where(user_id: [1,2,3]).joins(user: :categories).pluck('facebook_users.id')
FacebookUser.where( id: facebook_user_ids ).includes( user: :categories)
With
FacebookUser.includes( user: :categories)
you have eager loaded the user and his categories instead of the categories on facebook_user. So in order to avoid n+1 query you call then
f.user.categories
So why u just don't eager facebook_user's categories?
FacebookUser.includes(:categories)

Excluding results in has_many :through relation in Rails 3

I am trying to select groups which the #current_user is NOT a member of
The relevant parts of my models are as follows:
class Group < ActiveRecord::Base
belongs_to :user
has_many :group_memberships
has_many :members, :class_name => "User", :through=>:group_memberships
...
class User < ActiveRecord::Base
has_many :group_memberships, :foreign_key => 'member_id'
has_many :groups, :through => :group_memberships
...
class GroupMembership < ActiveRecord::Base
belongs_to :member, :class_name=>"User"
belongs_to :group
end
Thanks!
You could try and do something like:
#groups = Group.where("id NOT IN (?)", current_user.groups)
More information can be found in the Active Record Query.
have a method like this:
def group_ids_not_a_member_of
# get all group_ids and subtract out the ids that he is a member of
Group.pluck('id') - current_user.groups.map(&:id)
end
then
user.group_ids_not_a_member_of

rails 3.1 - has_one, through

Is it possible to make a has_one relationship work like this?
I would like to be able able to load records like this:
#person = Person.find(1) => {Person id: 1, favorite_house_id: 10}
#person.favorite_house => {House id: 10....)
class Person < ActiveRecord::Base
has_many :houses, through: :person_houses
has_one :favorite_house, through: :person_houses
end
class PersonHouse < ActiveRecord::Base
belongs_to :house
belongs_to :person
end
class House < ActiveRecord::Base
has_many :people, through: :person_houses
end
Replace the has_one relation of Person by:
belongs_to :favorite_house, :class_name => "House"
Do not forget to create a column favorite_house_id in the table of Person.

Has_many, through association

Warning:Total Rails Newb (TRN). This should be a pretty basic question so I'm hoping someone can spare a couple mins to help shed some light.
Let's say I have the following models: User, Group, and Member
A user can have many groups (let's say friends, family, etc)
A group can have many members, namely other users.
How would I structure this?
Initially I tried this:
class User < ActiveRecord::Base
has_many :groups
has_many :groups, :through => :members
end
class Groups < ActiveRecord::Base
has_many :users, :through => :members
belongs_to :user
end
class Member < ActiveRecord::Base
belongs_to :group
belongs_to :user
end
However this gave me an error in User so I changed
has_many :groups, :through => :members
to
has_many :memberships, :through => :members, :source => :groups
Still getting an error about missing association when I try to do
group = Group.new
group.user.new
It will be useful: http://railscasts.com/episodes/47-two-many-to-many
class User < ActiveRecord::Base
has_many :members
has_many :groups, :through => :members
has_many :groups_as_owner, :class_name => "Group"
end
class Groups < ActiveRecord::Base
has_many :members
has_many :users, :through => :members
belongs_to :owner, :class_name => "User", :foreign_key => :user_id
end
class Member < ActiveRecord::Base
belongs_to :group
belongs_to :user
end
basically has_many-through associations are n:m associations (join-tables) that (shall) have more attributes than just the id's of the joined record ids...
so you have a table Groups (with an id), a table Users (with an id) and a table Members (no id, but user_id and group_id)
basically, what you did is nearly correct, just think about how you access a group from a user or vice versa....
a user would first look up its member information and through that member information get access to the group information ... and vice versa for a group
so you first set up
has_many :members
and then call
has_many :groups, :through => :members
all you need is
class User < ActiveRecord::Base
has_many :members
has_many :groups, :through => :members
end
class Groups < ActiveRecord::Base
has_many :members
has_many :users, :through => :members
end
class Member < ActiveRecord::Base
belongs_to :group
belongs_to :user
end
and you have another bug in your code above
you might want to use
user = group.users.new
instead of
user = group.user.new
Try this structure:
class User < ActiveRecord::Base
has_many :members
has_many :groups, :through => :members
end
class Groups < ActiveRecord::Base
has_many :members
has_many :users, :through => :members
end
class Member < ActiveRecord::Base
belongs_to :group
belongs_to :user
end
Also take a look at has_and_belongs_to_many, if you don't need to do with class Member then you should use has_and_belongs_to_many. In this case don't forget to create joining table in the database