Created
March 16, 2010 19:44
-
-
Save jtrupiano/334413 to your computer and use it in GitHub Desktop.
Should factory_girl bypass :attr_accessible by default?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# factory_girl has difficulty playing nicely with attr_accessible. | |
class Article | |
belongs_to :owner | |
attr_accessible :name | |
end | |
Factory.define(:article) do |a| | |
a.association :owner | |
a.sequence(:name) {|i| "Article #{i}"} | |
end | |
# The core problem is that attr_accessible denies factory_girl's assignment of those specific attributes. | |
# It forces us as consumers of the Factory to use the :build strategy and then manually assign those | |
# attributes which is long-winded and annoying to say the least. | |
@article = Factory.build(:article) | |
@article.owner = Factory(:owner) | |
# Anyone who's used attr_accessible before will recognize a similar pattern in their controllers. | |
def create | |
@article = Article.new(params[:article]) | |
@article.owner = admin? ? User.find(params[:article][:owner_id]) : current_user | |
@article.save | |
end | |
# For the controller case, we can leverage Ryan Bates' trusted-params plugin. | |
def create | |
params[:article].trust(:owner_id) if admin? | |
@article = Article.new(params[:article]) | |
@article.save | |
end | |
# So great, now I can do my functional tests. But what about my unit tests? | |
Factory(:article) # ==> error that owner is not set!! FUCK! | |
# So how can I get trusted-params-like functionality in my models/unit tests? | |
# One way that factory_girl could solve this would be to support a before_save callback, e.g. | |
Factory.define(:article, :parent => :attrs_for_article) do |a| | |
a.before_save {|article| article.owner ||= Factory(:owner) } | |
end | |
# This is looking like a bit of a yak though. Another option would be to bake in a :bypass_attr_accessible | |
# option for factories, e.g. | |
Factory(:article, :bypass_attr_accessible) | |
# But even this has its shortcomings. Now I as a consumer of the Article factory must remember that it's | |
# protected some attributes (which I'm not even passing in because they're part of the default factory | |
# definition). | |
# Perhaps a better solution is to add it as an option to the factory definition? | |
Factory.define(:article, :attr_accessible => :bypass) do |a| | |
a.association :owner | |
a.sequence(:name) {|i| "Article #{i}"} | |
end | |
# What is nice about this is we can very easily test our authorization in our functional tests. | |
def test_should_update_article_as_a_regular_user | |
@user = Factory(:user) | |
@name = 'Something now in the factory' | |
@article = Factory(:article, :name => @name, :owner => @user) | |
log_in @user | |
# keep in mind the article factory will create a brand new user... | |
put :update, :id => @article.id, :article => Factory.attributes_for(:article) | |
# ...which allows us to test that we were prevented from changing that! | |
assert_equal @article.reload.owner, @current_user | |
assert_not_equal @article.name, @name | |
end | |
# Or better yet, should factory_girl just bypass attr_accessible by default? |
Hey Andy, honestly I don't remember. I actually have a sneaking suspicion that this gist is inaccurate...that attr_accessible was not giving me problems.
attr_accessible does seem to be causing the problems in my use of factory_girl for the record... so I wouldn't be surprised if it was your problem, too.
Also, for the poor soul who googled your way here 3 years in the future, it looks like factory_girl callbacks have since solved this, in a manner similar to the before_save suggestion above: http://codeulate.com/2009/11/factory_girl-callbacks/
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi John. What did you end up doing to use factory_girl and attr_accessible together? (rails 2.3.5, factory_girl 1.3.2)