Add `with_primary_key` to AssociationMatchers

This commit is contained in:
Peter Marsh 2014-10-07 22:05:16 +01:00
parent a009c83943
commit 0f34231d08
3 changed files with 137 additions and 0 deletions

View File

@ -27,11 +27,14 @@
* Tweak `allow_value` failure message so that it reads a bit nicer when listing
existing errors.
* Add ability to test `:primary_key` option on associations. ([#597])
[#591]: https://github.com/thoughtbot/shoulda-matchers/pull/591
[#592]: https://github.com/thoughtbot/shoulda-matchers/pull/592
[#588]: https://github.com/thoughtbot/shoulda-matchers/pull/588
[#584]: https://github.com/thoughtbot/shoulda-matchers/pull/584
[#593]: https://github.com/thoughtbot/shoulda-matchers/pull/593
[#597]: https://github.com/thoughtbot/shoulda-matchers/pull/597
# 2.7.0

View File

@ -100,6 +100,28 @@ module Shoulda
# should belong_to(:ancient_city).class_name('City')
# end
#
# ##### with_primary_key
#
# Use `with_primary_key` to test usage of the `:primary_key` option.
#
# class Person < ActiveRecord::Base
# belongs_to :great_country, primary_key: 'country_id'
# end
#
# # RSpec
# describe Person do
# it do
# should belong_to(:great_country).
# with_primary_key('country_id')
# end
# end
#
# # Test::Unit
# class PersonTest < ActiveSupport::TestCase
# should belong_to(:great_country).
# with_primary_key('country_id')
# end
#
# ##### with_foreign_key
#
# Use `with_foreign_key` to test usage of the `:foreign_key` option.
@ -295,6 +317,24 @@ module Shoulda
# should have_many(:hopes).class_name('Dream')
# end
#
# ##### with_primary_key
#
# Use `with_primary_key` to test usage of the `:primary_key` option.
#
# class Person < ActiveRecord::Base
# has_many :worries, primary_key: 'worrier_id'
# end
#
# # RSpec
# describe Person do
# it { should have_many(:worries).with_primaryu_key('worrier_id') }
# end
#
# # Test::Unit
# class PersonTest < ActiveSupport::TestCase
# should have_many(:worries).with_primary_key('worrier_id')
# end
#
# ##### with_foreign_key
#
# Use `with_foreign_key` to test usage of the `:foreign_key` option.
@ -511,6 +551,24 @@ module Shoulda
# should have_one(:contract).dependent(:nullify)
# end
#
# ##### with_primary_key
#
# Use `with_primary_key` to test usage of the `:primary_key` option.
#
# class Person < ActiveRecord::Base
# has_one :job, primary_key: 'worker_id'
# end
#
# # RSpec
# describe Person do
# it { should have_one(:job).with_primary_key('worker_id') }
# end
#
# # Test::Unit
# class PersonTest < ActiveSupport::TestCase
# should have_one(:job).with_primary_key('worker_id')
# end
#
# ##### with_foreign_key
#
# Use `with_foreign_key` to test usage of the `:foreign_key` option.
@ -814,6 +872,11 @@ module Shoulda
self
end
def with_primary_key(primary_key)
@options[:primary_key] = primary_key
self
end
def validate(validate = true)
@options[:validate] = validate
self
@ -846,6 +909,7 @@ module Shoulda
macro_correct? &&
(polymorphic? || class_exists?) &&
foreign_key_exists? &&
primary_key_exists? &&
class_name_correct? &&
join_table_correct? &&
autosave_correct? &&
@ -928,10 +992,19 @@ module Shoulda
end
end
def macro_supports_primary_key?
macro == :belongs_to ||
([:has_many, :has_one].include?(macro) && !through?)
end
def foreign_key_exists?
!(belongs_foreign_key_missing? || has_foreign_key_missing?)
end
def primary_key_exists?
!macro_supports_primary_key? || primary_key_correct?(model_class)
end
def belongs_foreign_key_missing?
macro == :belongs_to && !class_has_foreign_key?(model_class)
end
@ -1034,6 +1107,19 @@ module Shoulda
end
end
def primary_key_correct?(klass)
if options.key?(:primary_key)
if option_verifier.correct_for_string?(:primary_key, options[:primary_key])
true
else
@missing = "#{klass} does not have a #{options[:primary_key]} primary key"
false
end
else
true
end
end
def foreign_key
if foreign_key_reflection
if foreign_key_reflection.respond_to?(:foreign_key)

View File

@ -29,6 +29,22 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
expect(Child.new).to belong_to(:parent)
end
it 'accepts an association using an existing custom primary key' do
define_model :parent
define_model :child, parent_id: :integer, custom_primary_key: :integer do
belongs_to :parent, primary_key: :custom_primary_key
end
expect(Child.new).to belong_to(:parent).with_primary_key(:custom_primary_key)
end
it 'rejects an association with a bad :primary_key option' do
matcher = belong_to(:parent).with_primary_key(:custom_primary_key)
expect(belonging_to_parent).not_to matcher
expect(matcher.failure_message).to match(/Child does not have a custom_primary_key primary key/)
end
it 'accepts a polymorphic association' do
define_model :child, parent_type: :string, parent_id: :integer do
belongs_to :parent, polymorphic: true
@ -288,6 +304,22 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
expect(Parent.new).not_to have_many(:children)
end
it 'accepts an association using an existing custom primary key' do
define_model :child, parent_id: :integer
define_model :parent, custom_primary_key: :integer do
has_many :children, primary_key: :custom_primary_key
end
expect(Parent.new).to have_many(:children).with_primary_key(:custom_primary_key)
end
it 'rejects an association with a bad :primary_key option' do
matcher = have_many(:children).with_primary_key(:custom_primary_key)
expect(having_many_children).not_to matcher
expect(matcher.failure_message).to match(/Parent does not have a custom_primary_key primary key/)
end
it 'rejects an association with a bad :as option' do
define_model :child, caretaker_type: :string,
caretaker_id: :integer
@ -537,6 +569,22 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
expect(Person.new).to have_one(:detail).with_foreign_key(:detailed_person_id)
end
it 'accepts an association using an existing custom primary key' do
define_model :detail, person_id: :integer
define_model :person, custom_primary_key: :integer do
has_one :detail, primary_key: :custom_primary_key
end
expect(Person.new).to have_one(:detail).with_primary_key(:custom_primary_key)
end
it 'rejects an association with a bad :primary_key option' do
matcher = have_one(:detail).with_primary_key(:custom_primary_key)
expect(having_one_detail).not_to matcher
expect(matcher.failure_message).to match(/Person does not have a custom_primary_key primary key/)
end
it 'rejects an association with a bad :as option' do
define_model :detail, detailable_id: :integer,
detailable_type: :string