Closed Skulli closed 4 months ago
Thanks for opening this issue. I'll take a look at this as soon as possible. Meanwhile do you mind trying it out validating the select_option_id
instead of the whole object, to see if there's any difference?
validates :select_option_id, uniqueness: {scope: [:checklistable_type, :checklistable_id]}
@matsales28 Seeing this behaviour as well, and your alternative validation also fails in our code.
I was trying to reproduce it on my machine using this script, but it's passing, I might be missing something. Can you try to give more details or create a script that I can reproduce?
require 'bundler/inline'
gemfile(true) do
source 'https://rubygems.org'
gem 'shoulda-matchers'
gem 'activerecord'
gem 'sqlite3'
gem 'rspec'
gem 'byebug'
end
require 'active_record'
require 'shoulda-matchers'
require 'logger'
require 'byebug'
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
ActiveRecord::Base.logger = Logger.new(STDOUT)
# TODO: Update the schema to include the specific tables or columns necessary
# to reproduct the bug
ActiveRecord::Schema.define do
create_table :posts, force: true do |t|
t.string :body
t.bigint :author_id
t.bigint :polymorphic_id
t.string :polymorphic_type
end
create_table :authors, force: true do |t|
t.string :name
end
create_table :polymorphics, force: true do |t|
t.string :name
end
end
Shoulda::Matchers.configure do |config|
config.integrate do |with|
with.test_framework :rspec
with.library :active_record
with.library :active_model
end
end
RSpec.configure do |config|
config.include Shoulda::Matchers::ActiveRecord
config.include Shoulda::Matchers::ActiveModel
config.include Shoulda::Matchers::ActionController
end
class Post < ActiveRecord::Base
belongs_to :author
belongs_to :polymorphic, polymorphic: true
validates :author, uniqueness: { scope: [:polymorphic_id, :polymorphic_type] }
end
class Author < ActiveRecord::Base
has_many :posts
end
class Polymorphic < ActiveRecord::Base
has_many :posts, as: :polymorphic
end
RSpec.describe Post do
describe 'validations' do
subject { described_class.create(body: 'body', author: Author.create, polymorphic: Polymorphic.create) }
it do
is_expected.to validate_uniqueness_of(:author).scoped_to(:polymorphic_id, :polymorphic_type)
end
end
end
I found the issue in our particular case. The code that caused our issue is here:
Which I see fixes a few issues raised elsewhere with STI. In our case, we were relying on this particular behaviour elsewhere in our stack which is causing the unexpected result here. Tweaked our code, it appears we're off to the races again.
I found the issue in our particular case. The code that caused our issue is here:
5781741#diff-fb173d61ef0ac2aa7419231de02635b3d7753c8c35ffcfbc6efb365f2430ebcfL32
Which I see fixes a few issues raised elsewhere with STI. In our case, we were relying on this particular behaviour elsewhere in our stack which is causing the unexpected result here. Tweaked our code, it appears we're off to the races again.
That's great, do you mind sharing more about how your project was relying on this behavior? It would be nice to know so I could try to fix it in the gem, to avoid this bug in other projects.
Here's a script that I believe shows this kind of failure:
require 'bundler/inline'
gemfile(true) do
source 'https://rubygems.org'
gem 'shoulda-matchers'
gem 'activerecord'
gem 'sqlite3'
gem 'rspec'
end
require 'active_record'
require 'shoulda-matchers'
require 'logger'
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord::Schema.define do
create_table :assets, force: true do |t|
t.string :title
t.bigint :attachable_id
t.string :attachable_type
end
create_table :posts, force: true do |t|
t.string :body
end
end
Shoulda::Matchers.configure do |config|
config.integrate do |with|
with.test_framework :rspec
with.library :active_record
with.library :active_model
end
end
RSpec.configure do |config|
config.include Shoulda::Matchers::ActiveRecord
config.include Shoulda::Matchers::ActiveModel
config.include Shoulda::Matchers::ActionController
end
class Asset < ActiveRecord::Base
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
class Post < ActiveRecord::Base
# because we store "Post" in attachable_type now dependent: :destroy will work
has_many :assets, as: :attachable, dependent: :destroy
end
class GuestPost < Post
end
class MemberPost < Post
end
RSpec.describe Asset do
describe 'validations' do
subject { described_class.create(title: 'foo', attachable: GuestPost.create) }
it do
is_expected.to validate_uniqueness_of(:title).scoped_to(:attachable_id, :attachable_type)
end
end
end
Run rspec on this file and it should fail.
It is based on this suggestion from the Rails docs: https://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#module-ActiveRecord::Associations::ClassMethods-label-Polymorphic+Associations
@matsales28 I hope this is helpful!
Yes, that's very helpful! I'll work on a fix for this tomorrow! Thanks for your help @a-lavis
Description
After the update to 6.2 one of my uniqueness-specs fails
Reproduction Steps
Spec:
class:
Expected behavior
The spec should return true, did this until 6.2
Actual behavior
fails with
System configuration
shoulda_matchers version: 6.2.0 rails version: 7.1.3.2 ruby version: 3.2.3