From 6b6efeecc10d52589c0fa0f139843729a35e0a19 Mon Sep 17 00:00:00 2001 From: Sammy Larbi Date: Wed, 12 Mar 2014 07:05:29 -0500 Subject: [PATCH 1/4] add failing test that shows Paranoia not working with validates_uniquness_of --- test/paranoia_test.rb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test/paranoia_test.rb b/test/paranoia_test.rb index 173e86e2..af57b386 100644 --- a/test/paranoia_test.rb +++ b/test/paranoia_test.rb @@ -28,7 +28,7 @@ def setup! 'fail_callback_models' => 'deleted_at DATETIME', 'related_models' => 'parent_model_id INTEGER, parent_model_with_counter_cache_column_id INTEGER, deleted_at DATETIME', 'asplode_models' => 'parent_model_id INTEGER, deleted_at DATETIME', - 'employers' => 'deleted_at DATETIME', + 'employers' => 'name VARCHAR(32), deleted_at DATETIME', 'employees' => 'deleted_at DATETIME', 'jobs' => 'employer_id INTEGER NOT NULL, employee_id INTEGER NOT NULL, deleted_at DATETIME', 'custom_column_models' => 'destroyed_at DATETIME', @@ -685,6 +685,13 @@ def test_observers_not_notified_if_not_supported # essentially, we're just ensuring that this doesn't crash end + def test_validates_uniqueness_only_checks_non_deleted_records + a = Employer.create!(name: "A") + a.destroy + b = Employer.new(name: "A") + assert b.valid? + end + def test_i_am_the_destroyer expected = %Q{ Sharon: "There should be a method called I_AM_THE_DESTROYER!" @@ -909,6 +916,7 @@ def set_after_commit_on_destroy_callback_called class Employer < ActiveRecord::Base acts_as_paranoid + validates_uniqueness_of :name has_many :jobs has_many :employees, :through => :jobs end From a3179441055f62643a5015668d357e9d6086896e Mon Sep 17 00:00:00 2001 From: Sammy Larbi Date: Sun, 16 Mar 2014 09:08:12 -0500 Subject: [PATCH 2/4] Ensure uniqueness validation is scoped by deleted_at Fixes #114 --- lib/paranoia.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/paranoia.rb b/lib/paranoia.rb index 6549d7da..e379ed6d 100644 --- a/lib/paranoia.rb +++ b/lib/paranoia.rb @@ -237,3 +237,16 @@ def paranoia_sentinel_value end require 'paranoia/rspec' if defined? RSpec + +module ActiveRecord + module Validations + class UniquenessValidator < ActiveModel::EachValidator + protected + def build_relation_with_paranoia(klass, table, attribute, value) + relation = build_relation_without_paranoia(klass, table, attribute, value) + relation.and(klass.arel_table[klass.paranoia_column].eq(nil)) + end + alias_method_chain :build_relation, :paranoia + end + end +end From b6d60b556bf95e21e5243a97ee1ca978364252e4 Mon Sep 17 00:00:00 2001 From: Sammy Larbi Date: Sun, 21 Jun 2015 17:54:20 -0500 Subject: [PATCH 3/4] Test to ensure validates_uniqueness_of still works --- test/paranoia_test.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/paranoia_test.rb b/test/paranoia_test.rb index af57b386..c36e959c 100644 --- a/test/paranoia_test.rb +++ b/test/paranoia_test.rb @@ -692,6 +692,12 @@ def test_validates_uniqueness_only_checks_non_deleted_records assert b.valid? end + def test_validates_uniqueness_still_works_on_non_deleted_records + a = Employer.create!(name: "A") + b = Employer.new(name: "A") + refute b.valid? + end + def test_i_am_the_destroyer expected = %Q{ Sharon: "There should be a method called I_AM_THE_DESTROYER!" From 7232e2f5a76e8cad4c4a664d1ab33d87edcea12e Mon Sep 17 00:00:00 2001 From: Sammy Larbi Date: Sun, 21 Jun 2015 18:51:14 -0500 Subject: [PATCH 4/4] Fix `NameError: wrong constant name` on Ruby 1.9 Ruby 1.9's version of `Object.const_get` does not support namespaced constants, so this commit replaces it with `ActiveSupport`'s `#constantize` method. The tests were failing running JRuby on 1.9 mode. CRuby was not failing because it is not tested against 1.9. --- lib/paranoia.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/paranoia.rb b/lib/paranoia.rb index e379ed6d..3d8c5a4a 100644 --- a/lib/paranoia.rb +++ b/lib/paranoia.rb @@ -154,7 +154,7 @@ def restore_associated_records association_find_conditions = { association_foreign_key => self.id } end - association_class = Object.const_get(association_class_name) + association_class = association_class_name.constantize if association_class.paranoid? association_class.only_deleted.where(association_find_conditions).first.try!(:restore, recursive: true) end