Rails 4: can a child model belong_to two different

2019-09-04 03:57发布

问题:

In my initial Rails 4 app, I had the following models:

User
has_many :administrations
has_many :calendars, through: :administrations
has_many :comments

Calendar
has_many :administrations
has_many :users, through: :administrations
has_many :posts
has_many :comments, through: :posts

Administration
belongs_to :user
belongs_to :calendar

Post
belongs_to :calendar
has_many :comments

Comment
belongs_to :post
belongs_to :user

I just added a new Ad model to the app:

Ad
belongs_to :calendar

And now I would like to allow users to write comments about the ad records.

Can I use my existing Comment model and do something like:

Ad
belongs_to :calendar
has_many :comments

Comment
belongs_to :post
belongs_to :user

Or do I need to create a distinct "Comment" model, that I would call for instance AdComments or Feedback?

回答1:

You need to use polymorphic associations. Something on the lines of this:

class Comment < ActiveRecord::Base
  belongs_to :commentable, polymorphic: true
end

class Ad < ActiveRecord::Base
  has_many :comments, as: :commentable
end

class Product < ActiveRecord::Base
  has_many :comments, as: :commentable
end

And the migration would look like:

class CreateComments < ActiveRecord::Migration
  def change
    create_table :comments do |t|
      t.references :commentable, polymorphic: true, index: true
      t.timestamps null: false
    end
  end
end

I guess you already have the comments table, so you should rather change the table with

class ChangeComments < ActiveRecord::Migration
  def change
    change_table :comments do |t|
      t.rename :post_id, :commentable_id 
      t.string :commentable_type, null: false
    end
  end
end

Also beware, that if you have live data you should update the commentable_type field of all already existing comments to Post. You can either do it in a migration or from the console.

Comment.update_all commentable_type: 'Post'


回答2:

We don't need to use any new model, you can just refactor the current Comment model with polymorphic

So, a comment always belongs to a user, and belongs to a post or ad