Rails includes nested relations - ruby-on-rails-3

I need to query all posts from a specific user and include all comments and the user who belongs to the comment.
class User < ...
has_many :posts
has_many :comments
end
class Post < ...
belongs_to :user
has_many :comments
end
class Comment < ...
belongs_to :user
belongs_to :post
end
#posts = current_user.posts.include(:comments)
Is is possible to also get the comment user? I list a lot of posts and comments. I do not want to query each comment user.
Thx / Tobias

Try
#posts = current_user.posts.includes( :comments => :user)
Read more about it here

How about include at the relation definition statement?
:include
Specify second-order associations that should be eager loaded when this object is loaded.
class Post <
belongs_to :user
has_many :comments, :include => [:user], :limit => 5
end

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.

Rails sql complex query for public_activity

I'm using the public_activity gem with rails 4 to generate an activity feed. The models are as follows:
Class Post
has_many :comments
has_many :taggings
has_many :tags, through: :taggings
Class Comment
belongs_to :post
Class Tagging
belongs_to :post
belongs_to :tag
Class Tag
has_many :posts, through: :taggings
has_many :taggings
On the Tags#show action, I'd like to show a feed of all activities of posts and comments belonging to posts belonging to that particular tag. How do I write the query?
class TagsController
activities = PublicActivity::Activity.order("created_at desc").where('trackable_type =? OR trackable_type = ?', 'Post', 'Comment')
#activities =.....
SOLUTION.
Ok managed to get it working.
TagsController
def show
post_ids = #tag.posts.map(&:id)
comment_ids = Comment.where('post_id IN (?)', post_ids).map(&:id)
#activities = PublicActivity::Activity.
where("(trackable_id IN (?) AND trackable_type = 'Post')
or (trackable_id IN (?) AND trackable_type = 'Comment')", post_ids, comment_ids).
order("created_at desc")
end
It's ugly and unsatisfying but it gets the job done. Bonus points for whoever can optimize this query!

Ordering records by the number of associated records

Users can submit resources and post comments.
I want to show the users who are most 'active' by selecting the users who have submitted resources and comments and order the results from the user that has submitted the most resources and comments combined to the least.
**Resource**
has_many :users, :through => :kits
has_many :kits
belongs_to :submitter, class_name: "User"
**User**
has_many :resources, :through => :kits
has_many :kits
has_many :submitted_resources, class_name: "Resource", foreign_key: "submitter_id"
**Kits**
belongs_to :resource
belongs_to :user
**Comments**
belongs_to :user
I am new to this kind of sql in Rails. How can I get this record set?
First, you will need to add the comments association to the User model:
has_many :comments
With this, the simplest solution is to do this:
User.all.sort do |a,b|
(a.submitted_resources.count + a.comments.count) <=> (b.submitted_resources.count + b.comments.count)
end
This will get very slow, so if you want to do better you will want to add counter caches. In a migration:
def up
add_column :users, :submitted_resources_count, :integer
add_column :users, :comments_count, :integer
User.reset_column_information
User.find_each do |u|
u.update_attributes! \
:submitted_resources_count => u.submitted_resources.count,
:comments_count => u.comments.count
end
end
def down
add_column :users, :submitted_resources_count
add_column :users, :comments_count
end
Once you run this migration, you can change the original query to:
User.select('*, (submitted_resources_count + comments_count) AS activity_level').order('activity_level DESC')
This will very efficiently return all users in the proper order, and as a bonus each user will have a read-only attribute called activity_level that will give the exact submitted resources + comments count.

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

How to sort by created_at column of association in rails?

Here are my associations:
Class Post
belongs_to :user
has_many :favorites, :dependent => :destroy
has_many :favoriters, :through => :favorites, :source => :user
end
Class User
has_many :posts
has_many :favorites, :dependent => :destroy
has_many :favorited, :through => :favorites, :source => :post
end
Class Favorites
belongs_to :user, :post
end
I want to sort users' favorite posts by the created_at column of the Favorites association. However, this sorts by the Post created_at attribute, not the Favorites created_at attribute. How can I sort by the Favorites created_at attribute?
#posts=#user.favorited.order('created_at DESC')
You need to specify which table you want to use in the order by clause.
#posts = #user.favorited.order('posts.created_at DESC')
ought to do it.
One nice trick is to use the rails console when inspecting associations. Specifically, it helps to use the 'to_sql' method on Active Record queries you are performing.
For instance:
% bundle exec rails console
> u = User.last
> u.favorited.order('created_at DESC').to_sql
use this in your post model for set default order:
default_scope { order("created_at DESC") }