N + 1 Queries even with Eager loading in Rails 3.2 - ruby-on-rails-3

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)

Related

ActiveRecord querying through multiple joins

So below are my models:
post.rb
class Post < ActiveRecord::Base
has_many :taggings
has_many :tags, through: :taggings
has_many :collectables
has_many :collections, through: :collectables
end
tagging.rb
class Tagging < ActiveRecord::Base
belongs_to :post
belongs_to :tag, counter_cache: :posts_count
end
tag.rb
class Tag < ActiveRecord::Base
has_many :taggings
has_many :posts, through: :taggings
end
collectable.rb
class Collectable < ActiveRecord::Base
belongs_to :post
belongs_to :collection, counter_cache: :posts_count
end
collection.rb
class Collection < ActiveRecord::Base
has_many :collectables
has_many :posts
end
A Collection has many Posts, and a Post has many Tags. Now I'm trying to create a search bar that'll search for Collections by Posts that have particular Tags (tag.name is the search term). For instance, Collection 1 has a post that has the tag #cat. Now if the user searches for "cat", Collection 1 will show up in the results. I'm not sure how the query should look like for making this happen.
def self.search(search)
Collection.joins(:posts) ... ?
end
try this:
def self.search(search)
Collection.includes(posts: :tags).where(tags: {name: search})
end
Try This
def self.search(search)
Collection.joins(posts: :tags).where({tags: {name: search}})
end
You can use includes, eager_load and joins, but when you use joins then only it will take those collections who have the posts in all other cases, it will take all collections who have the posts and who don't have the posts.

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

Rails ActiveRecord query on existing collection

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)

How can I reference the same model twice and create the association in a multiple select form?

I have two classes (Game and Report) and want to link them with an additional attribute (default = yes or no).
The game should then have default_reports and optional_reports.
The association is then updated by selecting the default and optional reports in a select (multiple) in the games create/edit form.
I have tried using has_many and through as well as polymorphic associations, but nothing seems to fit the use case, where the associated objects are fixed and you only want to manage associations.
class Game < ActiveRecord::Base
has_many :game_reports
has_many :reports, :through => :game_reports
end
class Report < ActiveRecord::Base
has_many :game_reports
has_many :games, :through => :game_reports
end
class GameReport < ActiveRecord::Base
belongs_to :game
belongs_to :report
end
Any help is appreciated!
Thanks
this is just the model. the view and form to create the records is an entirely different matter.
you can always add a conditions option to has_many. I'm assuming you're going to add default to game_reports so change your class to something like.
class Game < ActiveRecord::Base
has_many :game_reports
has_many :reports, :through => :game_reports
has_many :default_reports, through: :game_reports, source: :report, conditions: { game_reports: { default: true } }
end
Rails 4.2+, use a Polymorphic association with scope and specify the foreign_key and foreign_type options.
class GameReport
belongs_to :report, :polymorphic => true
end
class Game
has_many :game_reports, :as => :report, :dependent => :destroy
has_many :reports, -> { where attachable_type: "GameReport"},
class_name: GameReport, foreign_key: :game_report_id,
foreign_type: :game_report_type, dependent: :destroy
end
Other approachs:
Rails Polymorphic Association with multiple associations on the same model

What's the rails way to include a field in a join model when listing an association?

So if I have the following relationship
class Item < ActiveRecord::Base
has_many :item_user_relationships
has_many :users, :through => :item_user_relationships
end
class User < ActiveRecord::Base
has_many :item_user_relationships
has_many :items, :through => :item_user_relationships
end
class ItemUserRelationship < ActiveRecord::Base
belongs_to :item
belongs_to :user
attr_accessible :role
end
What's the rails way to include the role attribute when listing all the Users of an Item?
#users = #item.users # I want to include the role as part of a user
Thanks!
UPDATE: I'm still having trouble with this. My goal is to get an array of User models that have their role included in the attributes.
I'm note sure if I understand you correctly, but maybe this is what you want?
#users = #item.users
#users.each do |user|
puts user.item_user_relationships.first.role
end