Tutorial :What is the best-practice, don't-work-yourself-into-a-corner way to add comments to many models?



Question:

Hi Stack Overflowers: I'm building a Ruby on Rails application that has several different models (e.g. Movie, Song, Photo) that I am storing movie clips, mp3s and photos. I'd like for users to be able to comment on any of those Models and have control over which comments are published.

Is the best practice to create a Comment model with:

belongs_to :movie  belongs_to :song  belongs_to :photo  

And then tie each Model with:

has_many :comments  

Then, I'm guessing in the Comment table, I'll need a foreign key for each Model:

comment, movie_id, song_id, photo_id  

Is this the correct way to build something like this, or is there a better way? Thanks in advance for your help.


Solution:1

Use acts_as_commentable. It creates a comment table with a commentable_type (model name of the commented-upon item) and commentable_id (the model's ID). Then all you need to do in your models:

class Photo < ActiveRecord::Base    acts_as_commentable  end  


Solution:2

Create a table to hold the relationships for each type of comment:

movie_comments, song_comments, photo_comments  

and then use:

class Movie < ActiveRecord::Base      has_many :movie_comments    has_many :comments, :through => :movie_comments    end    class MovieComment < ActiveRecord::Base    include CommentRelationship    belongs_to :comment    belongs_to :movie  end  

You can use a module (CommentRelationship) to hold all of the common functionality between your relationship tables (movie_comments)

This approach allows for the flexibility to be able to treat your comments differently depending on the type, while allowing for similar functionality between each. Also, you don't end up with tons of NULL entries in each column:

comment            | movie_id | photo_id | song_id  ----------------------------------------------------  Some comment            10         null      null  Some other comment     null        23        null  

Those nulls are definitely a sign you should structure your database differently.


Solution:3

Personally I would model it this way:

Media table (media_id, type_id, content, ...)  .  MediaType table (type_id, description, ... )  .  MediaComments table ( comment_id, media_id, comment_text, ...)  

After all, there is no difference to the database between a Song, Movie, or Photo. It's all just binary data. With this model you can add new "media types" without having to re-code. Add a new "MediaType" record, toss the data in the Media table.

Much more flexible that way.


Solution:4

I have no RoR Experience, but in this case you'd probably better off using inheritance on the database level, assuming your dbms supports this:

CREATE TABLE item (int id, ...);  CREATE TABLE movie (...) INHERITS (item);  CREATE TABLE song (...) INHERITS (item);  [...]  CREATE TABLE comments (int id, int item_id REFERENCES item(id));  

Another approach could be a single table with a type column:

CREATE TABLE item (int id, int type...);  CREATE TABLE comments (int id, int item_id REFERENCES item(id));  

As expressed before, I can't tell you how to exactly implement this using RoR.


Solution:5

The best idea is probably to do what Sarah suggests and use one of the existing plugins that handle commenting.

If you wish to roll your own, or just understand what happens under the covers, you need to read about Single Table Inheritance, the way Rails handles inheritance. Basically, you need a single comments table ala:

# db/migrate/xxx_create_comments  create_table :comments do |t|    t.string :type, :null => false    t.references :movies, :songs, :photos  end  

Now you can define your comment types as

class Comment < ActiveRecord::Base    validates_presence_of :body, :author    # shared validations go here  end    class SongComment < Comment    belongs_to :song  end    class MovieComment < Comment    belongs_to :movie  end    class PhotoComment < Comment    belongs_to :photo  end  

All your comments will be stored in a single table, comments, but PhotoComment.all only returns comments for which type == "Photo".


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »