0

I have a comment system with two tables: comments, and users. On the comment I want to record who the author was and also I want to notify any user that is mentioned in the comment with (@username). So I'm thinking I need to have an author_id on the comment, and also a comments_users table with the comment id and all the users ids that were mentioned. Would this be a correct way to accomplish it?:

User:

has_many :comments

Comment:

belongs_to :users, class_name: 'User', foreign_key: 'author_id'
has_many :users
sturoid
  • 2,501
  • 4
  • 20
  • 36
  • 1
    Yes!That would be the right approach. – Pavan Apr 12 '14 at 05:12
  • Thanks @Pavan. I will go with that then. To get the author from the comment could I say comment.author, and then to get the rest of the users would it be comment.users, or would that include the author in the query? – sturoid Apr 12 '14 at 05:17
  • `comment.author`? Have you defined your author model? comment=> `belongs_to user` So you can do `comment.user.name`(assuming you have name in users table) to get the author of the comment. – Pavan Apr 12 '14 at 05:34
  • You'd not need to define an `author` model - simply an `author` association, which can be done with my answer – Richard Peck Apr 12 '14 at 06:27

2 Answers2

3

The associations could be set up thus:

#app/models/user.rb
Class User < ActiveRecord::Base
    has_many :comments
    has_and_belongs_to_many :mentions, join_table: "comments_users", association_foriegn_key: "comment_id"
end

Class Comment < ActiveRecord::Base
    belongs_to :author, class_name: "User", foreign_key: "author_id"
    has_and_belongs_to_many :mentions, join_table: "comments_users", foreign_key: "comment_id"
end

#comments_users
comment_id | user_id

This will allow you to call:

@user.comments #-> shows comments user has authored
@user.mentions.first.comment #-> shows first comment user was mentioned in

@comment.author #-> shows user who authored comment
@comment.mentions.first.user #-> shows first user who was mentioned in comment

Update

HABTM still needs a table (Rails migration for has_and_belongs_to_many join table), but the difference is that it doesn't need a primary key column (just comment_id | user_id)

We've created a "self-referential" habtm relationship, meaning you don't need to "create" any records -- they should all be created already. The HABTM will just reference them. As such, you'll need to use the << ActiveRecord method to add records into your mentions collection:

#app/controllers/comments_controller.rb
Class CommentsController < ActiveRecord::Base
     def create
         @comment = Comment.new(comments_params)
         @comment.save_with_mentions
     end
end

#app/models/comment.rb
Class Comment < ActiveRecord::Base
    def save_with_mentions
        comment = self.save

        #do something to find mentioned users
        mentioned_users = User.where("user_id = 1") #example

        for user in mentioned_users do
            comment.mentions << user
        end
    end
end
Community
  • 1
  • 1
Richard Peck
  • 76,116
  • 9
  • 93
  • 147
  • 1
    Do I need to manually create the comments_users table? I'm getting strange errors where when I try to create or delete a comment, it says that the comments_users table is not found. I have done a migrate:reset. – sturoid Apr 13 '14 at 00:16
  • When I try to create a new mention I'm doing: @comment.mentions.create(user_id: user.id). Rails throws an error saying uninitialized constant Comment::Mention. Do you know what I'm doing wrong? – sturoid Apr 15 '14 at 23:37
  • Yep it's a problem with HABTM - Ill write an update to my answer for you when I get into thr office! – Richard Peck Apr 16 '14 at 07:13
1

There are always many ways to accomplish any given task, but I'm guessing you're looking for something like this for your models & associations.

User:

has_many :comments

The user model association looked right.

Comment:

belongs_to :author, class_name: 'User', foreign_key: 'user_id'
has_many :users

Note, the belongs_to should reference a model in singular-naming style (ie: user vs users). I think you're going to want to do a reference like comment.author to find the author of your comments. It is more typical to provide a foreign_key of user_id when referring to a User model to keep things clear, but then provide a clarifying association name like "author" or "creator" or whatever for reference as I showed above. So your Comments table would have a foreign_key of user_id to reference back to the Users table. This user would be referenced in Rails by the name "author".

The second part of your question that has to do with tracking other user references in your model sounds like a one-to-many from the comment-users table. So, that sounds like one option. Similar to your "author" comment, you may want to provide a clearer name like "tags" which can just be references to users. Another good option for this feature may be to set up a polymorphic table (essentially a flexible join table) if you plan to use this principle elsewhere in your app (like for referencing/tagging people in other elements like a photo or posting or something). It could provide greater flexibility for adding features and tracking these user references. A polymorphic table could have any name, but usually has an "-able" type name - like "taggable". Here's a useful reference: http://guides.rubyonrails.org/association_basics.html#polymorphic-associations

cjn
  • 1,331
  • 1
  • 16
  • 22