Search code examples
ruby-on-railsrubyruby-on-rails-3activerecordmass-assignment

Seed has_many relation using mass assignment


Here are my two models:

class Article < ActiveRecord::Base
  attr_accessible :content
  has_many :comments
end

class Comment < ActiveRecord::Base
  attr_accessible :content
  belongs_to :article
end

And I'm trying to seed the database in seed.rb using this code:

Article.create(
    [{
        content: "Hi! This is my first article!", 
        comments: [{content: "It sucks"}, {content: "Best article ever!"}]
    }], 
    without_protection: true)

However rake db:seed gives me the following error message:

rake aborted!
Comment(#28467560) expected, got Hash(#13868840)

Tasks: TOP => db:seed
(See full trace by running task with --trace)

It is possible to seed the database like this?

If yes a follow-up question: I've searched some and it seems that to do this kind of (nested?) mass assignment I need to add 'accepts_nested_attributes_for' for the attributes I want to assign. (Possibly something like 'accepts_nested_attributes_for :article' for the Comment model)

Is there a way to allow this similar to the 'without_protection: true'? Because I only want to accept this kind of mass assignment when seeding the database.


Solution

  • The reason you are seeing this error is that when you assign an associated model to another model (as in @article.comment = comment), it is expected that the right hand side be an actual object, not a hash of the object attributes.

    If you want to create an article by passing in parameters for a comment, you need to include accepts_nested_attributes_for :comments in the article model and add :comments_attributes to the attr_accesible list.

    This should allow for what you've written above.

    I don't believe it is possible to have conditional mass-assignment as this might compromise security (from a design standpoint).

    EDIT: You also need to change comments: [{content: "It sucks"}, {content: "Best article ever!"}] to comments_attributes: [{content: "It sucks"}, {content: "Best article ever!"}]