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.
They address this in 3.0.1 as there was also a related security vulnerability with it.
Good to hear – thanks for mentioning this, Frank!