Skip to content

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
RSpec matcher for ensuring a model is accepting nested attributes for an association, and accepting/rejecting the right values.
# Use: it { should accept_nested_attributes_for(:association_name).and_accept({valid_values => true}).but_reject({ :reject_if_nil => nil })}
RSpec::Matchers.define :accept_nested_attributes_for do |association|
match do |model|
@model = model
@nested_att_present = model.respond_to?("#{association}_attributes=".to_sym)
if @nested_att_present && @reject
model.send("#{association}_attributes=".to_sym,[@reject])
@reject_success = model.send("#{association}").empty?
end
if @nested_att_present && @accept
model.send("#{association}_attributes=".to_sym,[@accept])
@accept_success = ! (model.send("#{association}").empty?)
end
@nested_att_present && ( @reject.nil? || @reject_success ) && ( @accept.nil? || @accept_success )
end
failure_message_for_should do
messages = []
messages << "expected #{@model.class} to accept nested attributes for #{association}" unless @nested_att_present
messages << "expected #{@model.class} to reject values #{@reject.inspect} for association #{association}" unless @reject_success
messages << "expected #{@model.class} to accept values #{@accept.inspect} for association #{association}" unless @accept_success
messages.join(", ")
end
description do
desc = "accept nested attributes for #{expected}"
if @reject
desc << ", but reject if attributes are #{@reject.inspect}"
end
end
chain :but_reject do |reject|
@reject = reject
end
chain :and_accept do |accept|
@accept = accept
end
end
@maheeptathgur

hi paul,
firstly thank you for the code...is solved my problem for the rspec, however i would like to ask how can i test for the reject_if => proc { |attrs| attrs.all? { |key, val| val.blank?}}

@pauljamesrussell

Hi @maheeptathgur. I think you should just be able to do:

it { should accept_nested_attributes_for(:association_name).but_reject({ :val_1 => "", :val_2 => "" }) }

Let me know if that doesn't work, and I'll try and help some more.

@maheeptathgur

HI @pauljamesrussell
Thanks for the solution you gave, it worked, however i also happened to do the following and that too worked :)
it { should accept_nested_attributes_for(:association_name, :reject_if => {:val_1 => "", :val_2 => ""}) }
is it right to do this way?

@pauljamesrussell

Hi @maheeptathgur, no I'm afraid not - it'll just ignore the rejection test and not test for rejection. Your test will still pass, but it won't be proving what you want it to prove.

@mark-d-holmberg

Thank you!

@take

@pauljamesrussell the description message doesnt work.
When I changed it as below, it worked.

description do
  desc = "accept nested attributes for #{expected}"
  if @reject
    desc << ", but reject if attributes are #{@reject.inspect}"
  end
  desc
end
@dgilperez

+1 to @Takehiro-Adachi . Thanks Paul for sharing!

@JohnSmall

Great, it worked. But I thought RSpec already included Shoulda macros. I'm missing something here

@cgcardona

Thank you! Just what I was looking for

:+1:

@ashleyconnor

@JohnSmall - I believe the Shoulda macros do not support the reject_if: option.

@andreorvalho

@pauljamesrussell maybe you should do a pull request to the shoulda macros to use your features for rejection?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.