0
votes

I'm trying to design a comment system allowing users to post on other users' pages, through comments.

A user will have a comment on his page, which is posted by another user called "commenter."

1) Is the following code legit/functional/decent design?

2) Is it OK to have a renamed "commenter" user, in conjunction with an un-renamed "user", or should all association names of user always be renamed semantically?

3) Are there better ways to implement this design intent (e.g. not doing a has_many through:)?

class User < ActiveRecord::Base
  has_many :comments
  has_many :users,      through: :comments
  has_many :commenters, through: :comments, class_name: 'User'  
end

class Comment < ActiveRecord::Base
  belongs_to :user
  belongs_to :commenter, class_name: 'User'
end

NOTE:

I wish to allow users to comment on users, but also on other models, (e.g. characters, celebrities). So I would think having the comments table be used in various has_many through associations is called for.

users has many commenters through comments characters has many commenters through comments celebrities has many commenters through comments

3
Please, mark the answer you found more helpful as accepted. - Rafa Paez
Im still looking to see a solution with rails. I haven't had time to try that gem or test the rails code. I'm a bit reluctatnt. to mark now - ahnbizcad

3 Answers

4
votes

I believe your design is not going to work as it is - you are mixing has_many with has_many through. If I were you I would use an approach like this one:

class User < ActiveRecord::Base
  has_many :owned_comments, class_name: 'Comments', foreign_key: 'owner_id'
  has_many :posted_comments, class_name: 'Comments', foreign_key: 'commenter_id'
end

class Comment < ActiveRecord::Base
  belongs_to :owner, class_name: 'User'
  belongs_to :commenter, class_name: 'User'
end
1
votes

have to tried acts_as_commentable gem it give lot of other options as well like public,private comment https://github.com/jackdempsey/acts_as_commentable

1
votes

I implemented a similar functionality in mongoid and rails. The models were User, Friendship and Request. Its like User sends friend request to another user.

class User
  include Mongoid::Document
  include Mongoid::Timestamps
  devise :invitable, :database_authenticatable, :registerable, :recoverable,
    :rememberable, :trackable, :validatable, :confirmable
  ...
  has_many :requests_from, class_name: "Request", inverse_of: :requested_by
  has_many :requests_to, class_name: "Request", inverse_of: :requested_to
  has_many :friendships, inverse_of: :owner

  def friends
    #retrive all the friendships and collect users have sent me a request or being sent a request.
    fs = Friendship.any_of({:friend_id.in => [self.id]}, {:owner_id.in => [self.id]}).where(state: 'accepted')
    User.in(id: fs.collect{|i| [i.friend_id, i.owner_id]}.flatten - [self.id])
  end
end#User

class Friendship
  include Mongoid::Document
  include Mongoid::Timestamps

  field :state, type: String, default: 'pending'
  field :pending, type: Boolean, default: true

  belongs_to :owner, class_name: 'User'
  belongs_to :friend, class_name: "User"

  validates :state, inclusion: { in: ["pending", "accepted", "rejected"]}
  ...
end#Friendship

class Request
  include Mongoid::Document
  include Mongoid::Timestamps

  field :state, type: String, default: 'pending'

  belongs_to :requested_by, class_name: 'User', inverse_of: :requests_from
  belongs_to :requested_to, class_name: 'User', inverse_of: :requests_to

  validates :state, inclusion: { in: ["pending", "accepted", "rejected"]}
  ...
end#Request

I hope this helps.