Add `with_primary_key` to AssociationMatchers
This commit is contained in:
parent
a009c83943
commit
0f34231d08
3
NEWS.md
3
NEWS.md
|
@ -27,11 +27,14 @@
|
||||||
* Tweak `allow_value` failure message so that it reads a bit nicer when listing
|
* Tweak `allow_value` failure message so that it reads a bit nicer when listing
|
||||||
existing errors.
|
existing errors.
|
||||||
|
|
||||||
|
* Add ability to test `:primary_key` option on associations. ([#597])
|
||||||
|
|
||||||
[#591]: https://github.com/thoughtbot/shoulda-matchers/pull/591
|
[#591]: https://github.com/thoughtbot/shoulda-matchers/pull/591
|
||||||
[#592]: https://github.com/thoughtbot/shoulda-matchers/pull/592
|
[#592]: https://github.com/thoughtbot/shoulda-matchers/pull/592
|
||||||
[#588]: https://github.com/thoughtbot/shoulda-matchers/pull/588
|
[#588]: https://github.com/thoughtbot/shoulda-matchers/pull/588
|
||||||
[#584]: https://github.com/thoughtbot/shoulda-matchers/pull/584
|
[#584]: https://github.com/thoughtbot/shoulda-matchers/pull/584
|
||||||
[#593]: https://github.com/thoughtbot/shoulda-matchers/pull/593
|
[#593]: https://github.com/thoughtbot/shoulda-matchers/pull/593
|
||||||
|
[#597]: https://github.com/thoughtbot/shoulda-matchers/pull/597
|
||||||
|
|
||||||
# 2.7.0
|
# 2.7.0
|
||||||
|
|
||||||
|
|
|
@ -100,6 +100,28 @@ module Shoulda
|
||||||
# should belong_to(:ancient_city).class_name('City')
|
# should belong_to(:ancient_city).class_name('City')
|
||||||
# end
|
# 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
|
# ##### with_foreign_key
|
||||||
#
|
#
|
||||||
# Use `with_foreign_key` to test usage of the `:foreign_key` option.
|
# 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')
|
# should have_many(:hopes).class_name('Dream')
|
||||||
# end
|
# 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
|
# ##### with_foreign_key
|
||||||
#
|
#
|
||||||
# Use `with_foreign_key` to test usage of the `:foreign_key` option.
|
# Use `with_foreign_key` to test usage of the `:foreign_key` option.
|
||||||
|
@ -511,6 +551,24 @@ module Shoulda
|
||||||
# should have_one(:contract).dependent(:nullify)
|
# should have_one(:contract).dependent(:nullify)
|
||||||
# end
|
# 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
|
# ##### with_foreign_key
|
||||||
#
|
#
|
||||||
# Use `with_foreign_key` to test usage of the `:foreign_key` option.
|
# Use `with_foreign_key` to test usage of the `:foreign_key` option.
|
||||||
|
@ -814,6 +872,11 @@ module Shoulda
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def with_primary_key(primary_key)
|
||||||
|
@options[:primary_key] = primary_key
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
def validate(validate = true)
|
def validate(validate = true)
|
||||||
@options[:validate] = validate
|
@options[:validate] = validate
|
||||||
self
|
self
|
||||||
|
@ -846,6 +909,7 @@ module Shoulda
|
||||||
macro_correct? &&
|
macro_correct? &&
|
||||||
(polymorphic? || class_exists?) &&
|
(polymorphic? || class_exists?) &&
|
||||||
foreign_key_exists? &&
|
foreign_key_exists? &&
|
||||||
|
primary_key_exists? &&
|
||||||
class_name_correct? &&
|
class_name_correct? &&
|
||||||
join_table_correct? &&
|
join_table_correct? &&
|
||||||
autosave_correct? &&
|
autosave_correct? &&
|
||||||
|
@ -928,10 +992,19 @@ module Shoulda
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def macro_supports_primary_key?
|
||||||
|
macro == :belongs_to ||
|
||||||
|
([:has_many, :has_one].include?(macro) && !through?)
|
||||||
|
end
|
||||||
|
|
||||||
def foreign_key_exists?
|
def foreign_key_exists?
|
||||||
!(belongs_foreign_key_missing? || has_foreign_key_missing?)
|
!(belongs_foreign_key_missing? || has_foreign_key_missing?)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def primary_key_exists?
|
||||||
|
!macro_supports_primary_key? || primary_key_correct?(model_class)
|
||||||
|
end
|
||||||
|
|
||||||
def belongs_foreign_key_missing?
|
def belongs_foreign_key_missing?
|
||||||
macro == :belongs_to && !class_has_foreign_key?(model_class)
|
macro == :belongs_to && !class_has_foreign_key?(model_class)
|
||||||
end
|
end
|
||||||
|
@ -1034,6 +1107,19 @@ module Shoulda
|
||||||
end
|
end
|
||||||
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
|
def foreign_key
|
||||||
if foreign_key_reflection
|
if foreign_key_reflection
|
||||||
if foreign_key_reflection.respond_to?(:foreign_key)
|
if foreign_key_reflection.respond_to?(:foreign_key)
|
||||||
|
|
|
@ -29,6 +29,22 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
|
||||||
expect(Child.new).to belong_to(:parent)
|
expect(Child.new).to belong_to(:parent)
|
||||||
end
|
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
|
it 'accepts a polymorphic association' do
|
||||||
define_model :child, parent_type: :string, parent_id: :integer do
|
define_model :child, parent_type: :string, parent_id: :integer do
|
||||||
belongs_to :parent, polymorphic: true
|
belongs_to :parent, polymorphic: true
|
||||||
|
@ -288,6 +304,22 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
|
||||||
expect(Parent.new).not_to have_many(:children)
|
expect(Parent.new).not_to have_many(:children)
|
||||||
end
|
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
|
it 'rejects an association with a bad :as option' do
|
||||||
define_model :child, caretaker_type: :string,
|
define_model :child, caretaker_type: :string,
|
||||||
caretaker_id: :integer
|
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)
|
expect(Person.new).to have_one(:detail).with_foreign_key(:detailed_person_id)
|
||||||
end
|
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
|
it 'rejects an association with a bad :as option' do
|
||||||
define_model :detail, detailable_id: :integer,
|
define_model :detail, detailable_id: :integer,
|
||||||
detailable_type: :string
|
detailable_type: :string
|
||||||
|
|
Loading…
Reference in New Issue