Testing attr_accessible (and/or attr_protected)

I’ve been puzzling over how to test that attr_accessible has been set
for the correct columns; but the tests I’ve come up with so far seem
to fail to fail when I expect. I came across this old message from
this list:

http://www.mail-archive.com/[email protected]/msg01570.html

Which seemed like a plausible example, but my attempt (modeled on the
example) doesn’t work:

describe Article, ‘protected attributes’ do
it ‘should deny mass-assignment to the user_id’ do
lambda { article.update_attributes(:person_id => @person.id)
}.should raise_error
end
end

The lambda doesn’t raise an error, even though the attr_accessible
doesn’t include person_id.

Where am I stumbling here? Is it my beginner’s knowledge of rails, or
beginner’s knowledge of Ruby?

Thanks,

Iain

An attempt to assign protected attributes leads to the warning in your
log
and not doing actual assignment.
You can test it like this:

describe Article, ‘protected attributes’ do
it ‘should deny mass-assignment to the user_id’ do
RAILS_DEFAULT_LOGGER.should_receive(:warn) # I ain’t sure if it is
actually a warning, and I would just skip this check
article.update_attributes(:person_id => @person.id)
article.person_id.should == nil # or whatever it is before update
call
end
end

On Tue, Nov 2, 2010 at 3:36 AM, Iain E. Davis

update_attributes [1] doesn’t raise any exception when you try to
assign the attribute which is protected with
attr_accessible/attr_protected machinery (only warning in log is
printed).

So your options are:

  1. perform update_attributes for an attribute and then assert that the
    attribute didn’t change
  2. go a bit “meta” and implement something like Shoulda
    allow_mass_assignment_of matcher [2]

[1]

[2]
http://github.com/thoughtbot/shoulda/blob/master/lib/shoulda/active_record/matchers/allow_mass_assignment_of_matcher.rb

On Tue, Nov 2, 2010 at 3:36 AM, Iain E. Davis

I failed to mention I’m using Rails 2.3.8 and Rspec-1.3.x. I should
have said that right away.

On Tue, Nov 2, 2010 at 01:33, Alexey I. [email protected]
wrote:

An attempt to assign protected attributes leads to the warning in your log
Hmm… Maybe I should actually look at the log once in a while…

article.update_attributes(:person_id => @person.id)
article.person_id.should == nil # or whatever it is before update call

On Tue, Nov 2, 2010 at 02:13, Evgeniy D. [email protected]
wrote:

  1. perform update_attributes for an attribute and then assert that the attribute
    didn’t change

Buh. I wish I had thought of that. Seems rather obvious now…I
confess I was expecting something esoteric and thus didn’t stop to
think if there was a simple solution. :slight_smile:

To me, checking whether the attribute changed is more straight-forward
than implementing a custom matcher, at least at my current level of
experience (novice) with rails and rspec.

I suppose I need to be careful that the attribute change was rejected
for some other reason (bad data, for example). But that’s true of any
example/test.

On Tue, Nov 2, 2010 at 02:20, Wincent C. [email protected] wrote:

I’m the author of that message you linked to from three years ago. Things have
changed quite
a bit since then.

I suspected so! I guess I should have clued in when I didn’t find
anything about raising an error in the docs for update_attribute.

Oh! In the same vein, when looking at the docs/source for
update_attribute, I formed the expectation that update_attribute(s)
would return false if it failed. My new guess is that it returns false
if it fails to save the model…irregardless of whether the attribute
changes?

Thank you Alexey, Evgeniy, and Wincent!

Iain

On Tue, Nov 2, 2010 at 10:39 AM, Iain E. Davis
[email protected] wrote:

On Tue, Nov 2, 2010 at 02:13, Evgeniy D. [email protected] wrote:
I suppose I need to be careful that the attribute change was rejected
for some other reason (bad data, for example). But that’s true of any
example/test.

Note that Evgeniy’s two suggestions:

  1. perform update_attributes for an attribute and then assert that the
    attribute didn’t change
  2. go a bit “meta” and implement something like Shoulda
    allow_mass_assignment_of matcher

Represent two different philosophies.

The first, feels to me more like you are specifying/testing the
behavior of ActiveRecord rather than your own code. It indirectly
tests whether or not attr_accessible/attr_protected is in effect by
observing the effect on one of the methods which are effected by those
‘declarative’ methods.

In general I prefer to concentrate on specifying/testing the code I
write. The second approach is more compatible with that philosophy.
I trust that ActiveRecord correctly implements protected attributes,
what I want to prove is that my code is using them.

This is independent of whether or not a custom matcher is used. For
example Wincent’s implementation of the matcher takes the first
approach, while the shoulda macro instead examines whether or not the
model has an attribute set as accessible directly.

Now the shoulda approach is dependent a bit on the implementation in
activerecord, which is a reason to look for such plugins before trying
to write them yourself, an open-source plugin has more eyes on it and
will probably adapt to any changes before you run into them yourself.

And as Wincent points out, you don’t usually need to do such plumbing
yourself, there are lots of RSpec compatible matchers (including the
Shoulda matchers) freely available.


Rick DeNatale

Help fund my talk at Ruby Conf 2010:http://pledgie.com/campaigns/13677
Blog: http://talklikeaduck.denhaven2.com/
Github: rubyredrick (Rick DeNatale) · GitHub
Twitter: @RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale

On 02/11/2010, at 01:36, Iain E. Davis wrote:

describe Article, ‘protected attributes’ do
beginner’s knowledge of Ruby?
I’m the author of that message you linked to from three years ago.
Things have changed quite a bit since then.

Right now, I check for this stuff using a custom matcher:

mass_assignment.rb · GitHub

Which can be used like this:

article.should_not allow_mass_assignment_of(:person_id => @person.id)

Or:

article.should allow_mass_assignment_of(:person_id => @person.id)

I’m not the only one to have written custom matchers like this though;
if you Google (for “rspec custom matcher rails” or “rspec macro rails”)
you’ll probably find a bunch for doing this, and for other stuff (like
testing validations, associations etc).

Cheers,
Wincent

I suppose I need to be careful that the attribute change was rejected
for some other reason (bad data, for example). But that’s true of any
example/test.

Good catch, that’s why I think the Shoulda approach makes sense (since
otherwise you’re duplicating the Rails test suite which is supposed to
specify/exercise that functionality already)

To me, checking whether the attribute changed is more straight-forward
than implementing a custom matcher, at least at my current level of
experience (novice) with rails and rspec.

Okay, so that didn’t last very long. Suddenly, I was swimming in very
repetitive code in my _spec files…I could feel my eyes closing from
the ennui…

In light of that experience and the excellent points that Rick made, I
think I’ll go hunt down a custom matcher that checks that I actually
set the planned attr_accessible, rather than doing it the way I just
did it! I’ll start by looking at the link to Shoulda’s matcher,
kindly provided by Evgeniy earlier.

It works the other way, but the repetition was driving me crazy, and
as Rick says:

It indirectly tests whether or not attr_accessible/attr_protected is in effect
by observing the effect on
one of the methods which are effected by those ‘declarative’ methods.

I agree…I was at some level sort of aware of that but didn’t know
enough (yet) to overcome it. :slight_smile:

The second approach is more compatible with that philosophy. I trust that
ActiveRecord correctly
implements protected attributes, what I want to prove is that my code is using
them.

Exactly. The way I’ve begun to think is “…if I add a line[1] of code
to do X, will my test flag a failure if that line is not there?”. That
way I’m writing tests that insure that the code I’ve (or my team
has) written is correct, and not testing Rails/Authlogic/Rspec/etc.
themselves. :slight_smile:

Thanks again!

Iain

[1] “Line” is a bit misleading, since I could leave off a portion of
a line in the case of attr_accessible and similar pieces.