Create a gist now

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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

This comment has been minimized.

Show comment
Hide comment
@maheeptathgur

maheeptathgur May 10, 2012

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?}}

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

This comment has been minimized.

Show comment
Hide comment
@pauljamesrussell

pauljamesrussell May 10, 2012

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.

Owner

pauljamesrussell commented May 10, 2012

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

This comment has been minimized.

Show comment
Hide comment
@maheeptathgur

maheeptathgur May 13, 2012

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?

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

This comment has been minimized.

Show comment
Hide comment
@pauljamesrussell

pauljamesrussell Jun 1, 2012

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.

Owner

pauljamesrussell commented Jun 1, 2012

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

This comment has been minimized.

Show comment
Hide comment

Thank you!

@take

This comment has been minimized.

Show comment
Hide comment
@take

take Oct 9, 2012

@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

take commented Oct 9, 2012

@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

This comment has been minimized.

Show comment
Hide comment
@dgilperez

dgilperez Feb 19, 2013

+1 to @takehiro-adachi . Thanks Paul for sharing!

+1 to @takehiro-adachi . Thanks Paul for sharing!

@JohnSmall

This comment has been minimized.

Show comment
Hide comment
@JohnSmall

JohnSmall Apr 28, 2013

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

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

@cgcardona

This comment has been minimized.

Show comment
Hide comment
@cgcardona

cgcardona Jul 10, 2013

Thank you! Just what I was looking for

👍

Thank you! Just what I was looking for

👍

@ashleyconnor

This comment has been minimized.

Show comment
Hide comment
@ashleyconnor

ashleyconnor Sep 5, 2013

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

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

@andreorvalho

This comment has been minimized.

Show comment
Hide comment
@andreorvalho

andreorvalho Jan 29, 2014

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

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

@fullofcaffeine

This comment has been minimized.

Show comment
Hide comment
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment