From b618275a9d113d591e6043f0bb36c37157e9055f Mon Sep 17 00:00:00 2001 From: Jason Draper Date: Fri, 11 May 2012 11:36:22 -0400 Subject: [PATCH] create an entry for validates_uniquessness_of if one does not exist --- NEWS.md | 4 +++ README.md | 7 +---- .../validate_uniqueness_of_matcher.rb | 27 +++++++++++-------- .../validate_uniqueness_of_matcher_spec.rb | 9 ++----- 4 files changed, 23 insertions(+), 24 deletions(-) diff --git a/NEWS.md b/NEWS.md index 627c791c..e6682395 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,6 +3,10 @@ * Prefer Test::Unit to Minitest when loading integrations so that RubyMine is happy (#88). +* `validates_uniqueness_of` will now create a record if one does not exist. + Previously, users were required to create a record in the database before + using this matcher. + # v1.2.0 * `ensure_inclusion_of` now has an `in_array` parameter: diff --git a/README.md b/README.md index 80690476..b7c7881d 100644 --- a/README.md +++ b/README.md @@ -30,12 +30,7 @@ Matchers to test validations and mass assignments: it { should validate_presence_of(:body).with_message(/wtf/) } it { should validate_presence_of(:title) } it { should validate_numericality_of(:user_id) } - - # validates_uniqueness_of requires an entry to be in the database already - it "validates uniqueness of title" do - Post.create!(title: "My Awesome Post", body: "whatever") - should validate_uniqueness_of(:title) - end + it { should validate_uniqueness_of(:title) } end describe User do diff --git a/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb b/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb index 5014f7e3..123542a5 100644 --- a/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb +++ b/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb @@ -68,20 +68,25 @@ module Shoulda # :nodoc: def matches?(subject) @subject = subject.class.new @expected_message ||= :taken - has_existing? && - set_scoped_attributes && + set_scoped_attributes && validate_attribute? && validate_after_scope_change? end private - def has_existing? - if @existing = @subject.class.find(:first) - true - else - @failure_message = "Can't find first #{class_name}" - false + def existing + @existing ||= first_instance + end + + def first_instance + @subject.class.first || create_instance_in_database + end + + def create_instance_in_database + @subject.class.new.tap do |instance| + instance.send("#{@attribute}=", "arbitrary_string") + instance.save(:validate => false) end end @@ -90,7 +95,7 @@ module Shoulda # :nodoc: @options[:scopes].all? do |scope| setter = :"#{scope}=" if @subject.respond_to?(setter) - @subject.send("#{scope}=", @existing.send(scope)) + @subject.send("#{scope}=", existing.send(scope)) true else @failure_message = "#{class_name} doesn't seem to have a #{scope} attribute." @@ -114,7 +119,7 @@ module Shoulda # :nodoc: true else @options[:scopes].all? do |scope| - previous_value = @existing.send(scope) + previous_value = existing.send(scope) # Assume the scope is a foreign key if the field is nil previous_value ||= 0 @@ -144,7 +149,7 @@ module Shoulda # :nodoc: end def existing_value - value = @existing.send(@attribute) + value = existing.send(@attribute) if @options[:case_insensitive] && value.respond_to?(:swapcase!) value.swapcase! end diff --git a/spec/shoulda/active_model/validate_uniqueness_of_matcher_spec.rb b/spec/shoulda/active_model/validate_uniqueness_of_matcher_spec.rb index 92a14aac..d4a3f0bc 100644 --- a/spec/shoulda/active_model/validate_uniqueness_of_matcher_spec.rb +++ b/spec/shoulda/active_model/validate_uniqueness_of_matcher_spec.rb @@ -34,13 +34,8 @@ describe Shoulda::Matchers::ActiveModel::ValidateUniquenessOfMatcher do @matcher = validate_uniqueness_of(:attr) end - it "should fail to require a unique value" do - @model.should_not @matcher - end - - it "should alert the tester that an existing value is not present" do - @matcher.matches?(@model) - @matcher.negative_failure_message.should =~ /^Can't find first .*/ + it "does not not require a created instance" do + @model.should @matcher end end end