Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Polymorphic + STI uniqueness check #1624

Merged
merged 1 commit into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 13 additions & 1 deletion lib/shoulda/matchers/active_record/uniqueness/model.rb
Expand Up @@ -29,7 +29,19 @@ def next
end

def symlink_to(parent)
namespace.set(name, Class.new(parent))
table_name = parent.table_name

new_class = Class.new(parent) do
define_singleton_method :table_name do
table_name
end

define_singleton_method :base_class do
self
end
end

namespace.set(name, new_class)
end

def to_s
Expand Down
Expand Up @@ -1274,6 +1274,36 @@ def configure_validation_matcher(matcher)
scoped_to(:favoriteable_type)
end

context 'when polymorphic model is used on a STI model' do
it 'still works' do
columns = {
attachable_id: { type: :integer, options: { null: false } },
attachable_type: { type: :string, options: { null: false } },
title: { type: :string, options: { null: false } },
}

asset_model = define_model 'Asset', columns do
belongs_to :attachable, polymorphic: true

validates_uniqueness_of :title, scope: [:attachable_id, :attachable_type]

def attachable_type=(class_name)
super(class_name.constantize.base_class.to_s)
end
end

post_model = define_model 'Post', {} do
has_many :assets, as: :attachable, dependent: :destroy
end

guest_post_model = define_model 'GuestPost', {}, parent_class: post_model, table_name: 'posts'

asset = asset_model.create!(attachable: guest_post_model.create!, title: 'foo')

expect(asset).to validate_uniqueness_of(:title).scoped_to(:attachable_id, :attachable_type)
end
end

context 'if the model the *_type column refers to is namespaced, and shares the last part of its name with an existing model' do
it 'still works' do
define_class 'User'
Expand Down