Association matchers support :autosave option

has_one, has_many, belongs_to, and has_and_belongs_to_many relationships can
have an `:autosave` option, which causes the relevant associated records to be
automatically saved when their parent is saved.

This is based on a PR by @calebthompson, which I've brought up to date
with master.
This commit is contained in:
Elliot Winkler 2014-01-22 13:40:38 -07:00
parent 7fa7e67d88
commit 21e984cd28
3 changed files with 109 additions and 0 deletions

View File

@ -3,6 +3,8 @@
* Association matchers now test that the model being referred to (either
implicitly or explicitly, using `:class_name`) actually exists.
* Add ability to test `:autosave` option on associations.
# v 2.5.0
* Fix Rails/Test::Unit integration to ensure that the test case classes we are

View File

@ -28,6 +28,8 @@ module Shoulda # :nodoc:
# * <tt>dependent</tt> - tests that the association makes use of the
# dependent option.
# * <tt>:class_name</tt> - tests that the association resoves to class_name.
# * <tt>:autosave</tt> - tests that the association makes use of the
# autosave option.
# * <tt>:validate</tt> - tests that the association makes use of the validate
# option.
#
@ -48,6 +50,8 @@ module Shoulda # :nodoc:
# * <tt>:dependent</tt> - tests that the association makes use of the
# dependent option.
# * <tt>:class_name</tt> - tests that the association resolves to class_name.
# * <tt>:autosave</tt> - tests that the association makes use of the
# autosave option.
# * <tt>:validate</tt> - tests that the association makes use of the validate
# option.
#
@ -120,6 +124,11 @@ module Shoulda # :nodoc:
self
end
def autosave(autosave)
@options[:autosave] = autosave
self
end
def class_name(class_name)
@options[:class_name] = class_name
self
@ -163,6 +172,7 @@ module Shoulda # :nodoc:
class_exists? &&
foreign_key_exists? &&
class_name_correct? &&
autosave_correct? &&
conditions_correct? &&
join_table_exists? &&
validate_correct? &&
@ -266,6 +276,19 @@ module Shoulda # :nodoc:
false
end
def autosave_correct?
if options.key?(:autosave)
if option_verifier.correct_for_boolean?(:autosave, options[:autosave])
true
else
@missing = "#{name} should have autosave set to #{options[:autosave]}"
false
end
else
true
end
end
def conditions_correct?
if options.key?(:conditions)
if option_verifier.correct_for_relation_clause?(:conditions, options[:conditions])

View File

@ -116,6 +116,26 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
}.to fail_with_message(message)
end
it 'accepts an association with a matching :autosave option' do
define_model :parent, :adopter => :boolean
define_model :child, :parent_id => :integer do
belongs_to :parent, :autosave => true
end
expect(Child.new).to belong_to(:parent).autosave(true)
end
it 'rejects an association with a non-matching :autosave option with the correct message' do
define_model :parent, :adopter => :boolean
define_model :child, :parent_id => :integer do
belongs_to :parent, :autosave => false
end
message = 'Expected Child to have a belongs_to association called parent (parent should have autosave set to true)'
expect {
expect(Child.new).to belong_to(:parent).autosave(true)
}.to fail_with_message(message)
end
context 'an association with a :validate option' do
[false, true].each do |validate_value|
context "when the model has validate: #{validate_value}" do
@ -380,6 +400,26 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
}.to fail_with_message(message)
end
it 'accepts an association with a matching :autosave option' do
define_model :child, :parent_id => :integer
define_model :parent do
has_many :children, :autosave => true
end
expect(Parent.new).to have_many(:children).autosave(true)
end
it 'rejects an association with a non-matching :autosave option with the correct message' do
define_model :child, :parent_id => :integer
define_model :parent do
has_many :children, :autosave => false
end
message = 'Expected Parent to have a has_many association called children (children should have autosave set to true)'
expect {
expect(Parent.new).to have_many(:children).autosave(true)
}.to fail_with_message(message)
end
context 'validate' do
it 'accepts when the :validate option matches' do
expect(having_many_children(validate: false)).to have_many(:children).validate(false)
@ -530,6 +570,26 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
expect(having_one_detail).to have_one(:detail).class_name('Detail')
end
it 'accepts an association with a matching :autosave option' do
define_model :detail, :person_id => :integer, :disabled => :boolean
define_model :person do
has_one :detail, :autosave => true
end
expect(Person.new).to have_one(:detail).autosave(true)
end
it 'rejects an association with a non-matching :autosave option with the correct message' do
define_model :detail, :person_id => :integer, :disabled => :boolean
define_model :person do
has_one :detail, :autosave => false
end
message = 'Expected Person to have a has_one association called detail (detail should have autosave set to true)'
expect {
expect(Person.new).to have_one(:detail).autosave(true)
}.to fail_with_message(message)
end
it 'accepts an association with a valid :class_name option' do
define_model :person_detail, person_id: :integer
define_model :person do
@ -712,6 +772,30 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
}.to fail_with_message(message)
end
it 'accepts an association with a matching :autosave option' do
define_model :relatives, :adopted => :boolean
define_model :person do
has_and_belongs_to_many :relatives, :autosave => true
end
define_model :people_relative, :person_id => :integer,
:relative_id => :integer
expect(Person.new).to have_and_belong_to_many(:relatives).autosave(true)
end
it 'rejects an association with a non-matching :autosave option with the correct message' do
define_model :relatives, :adopted => :boolean
define_model :person do
has_and_belongs_to_many :relatives
end
define_model :people_relative, :person_id => :integer,
:relative_id => :integer
message = 'Expected Person to have a has_and_belongs_to_many association called relatives (relatives should have autosave set to true)'
expect {
expect(Person.new).to have_and_belong_to_many(:relatives).autosave(true)
}.to fail_with_message(message)
end
context 'validate' do
it 'accepts when the :validate option matches' do
expect(having_and_belonging_to_many_relatives(validate: false)).