Reputation: 2040
I have users, posts and comments. User can post only one comment to each post.
class User < ActiveRecord::Base
has_many :posts
has_many :comments
end
class Post < ActiveRecord::Base
has_many :comments
belongs_to :user
end
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :post
end
On userpage (http://host/users/1
for example) I want to show all posts where the given user has commented. Each post then will have all other comments.
I can do something like this in my User controller:
def show
@user = User.find(params[:user_id])
@posts = []
user.comments.each {|comment| @posts << comment.post}
end
This way I will find User, then all his comments, then corresponding post to each comment, and then (in my view) for each post I will render post.comments. I'm totally new in Rails, so I can do this =) But I think it's somehow bad and there is a better way to do this, maybe I should use scopes or named_scopes (don't know yet what this is, but looks scary).
So can you point me out to the right direction here?
Upvotes: 2
Views: 2377
Reputation: 1052
When you got the user, you have the associations to his posts and each post has his comments. You could write: (I don't know the names of your table fields, so i named the text text)
# In Controller
@user = User.find(params[:user_id]).include([:posts, :comments])
# In View
@user.posts.each do |post|
post.text
# Comments to the Post
post.comments.each do |comment|
comment.text
end
end
I haven't tested the code, so there could be some errors.
Upvotes: 0
Reputation: 3950
You could define an association which retrieves all the posts with comments in a single query. Keeping it in the model reduces the complexity of your controllers, enables you to reuse the association and makes it easier to unit test.
class User < ActiveRecord::Base
has_many :posts_with_comments, :through => :comments, :source => :post
# ...
end
:through
is an option for has_many
to specify a join table through which to perform the query. We need to specify the :source
as Rails wouldn't be able to infer the source from :post_with_comments
.
Lastly, update your controller to use the association.
def show
@user = User.find(params[:user_id])
@posts = @user.posts_with_comments
end
To understand more about :through
and :source
take a look at the documentation.
Upvotes: 5