Skip to content


Rails 3.0 upgrade: Watch out for differences in mass assignment checks on has_many :through associations

Please see comment below – looks like this has been taken care of in Rails 3.0.1.

While porting a small Rails application, Listable, to Rails 3.0, I found an interesting difference in the behavior of the two frameworks: attr_accessible on a model used for a join relation between two entities works when using ‘<<’ to add records in Rails 3.0, while in Rails prior to 3.0 it is silently ignored.   It took me a moment to figure out what was happening, so I figured I’d leave a note here in case it helps someone else in porting their app to the newest Rails framework.

Taking a step back, here is a simple case that demonstrates the difference between Rails version 2 and Rails version 3 with respect to << (aliased as ‘concat’ and ‘push’ in the ActiveRecord framework) when adding to a collection established using has_many :through.  Given three models: User, List, and UserListLink (which has foreign keys for user and list):

class User < ActiveRecord::Base
has_many :user_list_links, :dependent => :destroy
has_many :lists, :through => :user_list_links
end
class List < ActiveRecord::Base
has_many :user_list_links, :dependent => :destroy
has_many :users, :through => :user_list_links
end
class UserListLink < ActiveRecord::Base
belongs_to :user
belongs_to :list
end

In both Rails 2 and 3, the following works:

u = User.create
l = List.create
u.lists << l

However, if you add attr_accessible [] to UserListLink, under Rails 3 the UserListLink that is automatically generated will have nil/null values for both list_id and user_id. You’ll see the expected message in the Rails log, “WARNING: Can’t mass-assign protected attributes: list_id, user_id”, which indicates that Rails uses mass assignment to create this intermediary object. In my case, removing the attr_accessible line in my code allowed ‘<<’ to work as it did before upgrading to Rails 3.

I’m not sure how I feel about the change in behavior in ActiveRecord 3 where mass assignment protection is triggered by the ‘concat’ method on a has_many :through relationship.  I suppose whether or not this is ‘correct’ behavior depends on whether there is a chance for user-generated data to be passed into the attribute hash used to construct the intermediary object.  If so, this is probably a nice fix in ActiveRecord 3.    Otherwise, though, it may help to bypass the mass assignment check when saving intermediary objects using concat.

Posted in Rails, Ruby.


2 Responses

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.

  1. Frank Lakatos says

    They address this in 3.0.1 as there was also a related security vulnerability with it.

  2. Justin Leitgeb says

    Good to hear – thanks for mentioning this, Frank!



Some HTML is OK

or, reply to this post via trackback.