Skip to content

Commit

Permalink
Fail when no scopes on uniq matcher but scopes on validation
Browse files Browse the repository at this point in the history
Change behavior of `validate_uniqueness_of` when the matcher is not
qualified with any scopes, but your validation is. Previously the
following test would pass when it now fails:

    class Post < ActiveRecord::Base
      validate :slug, uniqueness: { scope: :user_id }
    end

    describe Post do
      it { should validate_uniqueness_of(:slug) }
    end
  • Loading branch information
mcmire committed May 22, 2015
1 parent 1cb872a commit 6ac7b81
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 5 deletions.
14 changes: 14 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,20 @@
(which is to permit this) is misleading, as the test that you write by using
`allow_value` is different from the test that actually ends up getting run.

* Change behavior of `validate_uniqueness_of` when the matcher is not
qualified with any scopes, but your validation is. Previously the following
test would pass when it now fails:

``` ruby
class Post < ActiveRecord::Base
validate :slug, uniqueness: { scope: :user_id }
end

describe Post do
it { should validate_uniqueness_of(:slug) }
end
```

### Bug fixes

* So far the tests for the gem have been running against only SQLite. Now they
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,8 @@ def matches?(subject)
@expected_message ||= :taken
@all_records = @subject.class.all

set_scoped_attributes &&
scopes_match? &&
set_scoped_attributes &&
validate_everything_except_duplicate_nils_or_blanks? &&
validate_case_sensitivity? &&
validate_after_scope_change? &&
Expand All @@ -271,6 +272,37 @@ def matches?(subject)

private

def validation
@subject.class._validators[@attribute].detect do |validator|
validator.is_a?(::ActiveRecord::Validations::UniquenessValidator)
end
end

def scopes_match?
expected_scopes = Array.wrap(@options[:scopes])

if validation
actual_scopes = Array.wrap(validation.options[:scope])
else
actual_scopes = []
end

if expected_scopes == actual_scopes
true
else
@failure_message = "Expected validation to be scoped to " +
"#{expected_scopes}"

if actual_scopes.present?
@failure_message << ", but it was scoped to #{actual_scopes}."
else
@failure_message << ", but it was not scoped to anything."
end

false
end
end

def allows_nil?
if @options[:allow_nil]
ensure_nil_record_in_database
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,11 @@
expect(record).not_to validate_uniqueness
end

it 'accepts if the scope is unset beforehand' do
it 'rejects if the scope is unset beforehand' do
record = build_record_validating_uniqueness(
scopes: [ build_attribute(name: :scope, value: nil) ]
)
expect(record).to validate_uniqueness
expect(record).not_to validate_uniqueness
end
end

Expand All @@ -130,8 +130,8 @@
end
end

define_method(:build_attribute) do |options|
options.merge(
define_method(:build_attribute) do |attribute_options|
attribute_options.merge(
column_type: column_type,
value_type: value_type,
array: array
Expand Down

0 comments on commit 6ac7b81

Please sign in to comment.