globalize3-validations 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NzVlMTVhMjEyMmI4YTg1NjM3OTgzY2RmMmIxNjc2YjRjZmExOWI2Ng==
5
+ data.tar.gz: !binary |-
6
+ ZGMxOGM1M2UyNDlkMGU3NGRmODI0MDIyNjk4ODE5YjJmMzI4MTYxMw==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ YWZmNDg3ZmQ0MjZiZjA0MWNhODEyYWI5MWJlNGExODk5YTBmYmJmZDA0MmNi
10
+ MmNhMmM5OTZjMWU3MjExNmM4MWU4MTBjMWJlMzE0YmUyNTZhM2ZiMjM0OWZi
11
+ OWE1ODAwMDgzYWVkNmNkY2I0MTIxM2UzNTUwNmIwNjY4ODUyOTE=
12
+ data.tar.gz: !binary |-
13
+ NGM3OWVkNTIyZTU2MDNhZDI4NTQ5YmY5MDg3MjA5ZGNhMmM3NjdlYWYwMDRj
14
+ ZDYyMGFlYWUyNWIzODJmZDlhZWI3NTQ1MzU4ZDY4ZWQwMzg0NmQyNDhhZjUy
15
+ YjZlZGNlNjZlOTZkZjkxYmNlNjdkN2MwZjY2OTRhMjM1MWE4YjA=
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ gemfiles/*.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
@@ -0,0 +1,10 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
5
+ - 1.9.3
6
+ - ree
7
+ script: "bundle exec rake spec"
8
+ gemfile:
9
+ - gemfiles/rails_3.1.gemfile
10
+ - gemfiles/rails_3.2.gemfile
@@ -0,0 +1,11 @@
1
+ appraise 'rails-3.0' do
2
+ gem 'rails', '~> 3.0.0'
3
+ end
4
+
5
+ appraise 'rails-3.1' do
6
+ gem 'rails', '~> 3.1.0'
7
+ end
8
+
9
+ appraise 'rails-3.2' do
10
+ gem 'rails', '~> 3.2.0'
11
+ end
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in globalize3-validations.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 emjot GmbH & Co. KG
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,64 @@
1
+ # globalize3-validations
2
+
3
+ [![Build Status](https://travis-ci.org/emjot/globalize3-validations.png?branch=master)](https://travis-ci.org/emjot/globalize3-validations)
4
+
5
+ Provides a uniqueness validator which can be used with globalize3 translated models.
6
+
7
+ ## Compatibility
8
+
9
+ Works with rails 3.1 and 3.2.
10
+
11
+ Rails 3.0 is not fully supported (case insensitive validation doesn't work).
12
+
13
+ The validator is based on the activerecord 3.2 uniqueness validator.
14
+
15
+
16
+ ## Installation
17
+
18
+ Add this line to your application's Gemfile:
19
+
20
+ gem 'globalize3-validations'
21
+
22
+ And then execute:
23
+
24
+ $ bundle
25
+
26
+ Or install it yourself as:
27
+
28
+ $ gem install globalize3-validations
29
+
30
+ ## Usage
31
+
32
+ Provides a `GlobalizedUniquenessValidator` which checks whether
33
+ the value of the specified attributes are unique across the system.
34
+
35
+ See validates_uniqueness_of in ActiveRecord::Validations::ClassMethods for further explanation.
36
+ This validator basically works the same, but additionally respects globalize3 model translations.
37
+ Also, you can use :locale when specifying the :scope option. This will scope the validation to the current locale.
38
+
39
+ For instance, if you want to validate that a product title is unique in each locale:
40
+
41
+ class Product < ActiveRecord::Base
42
+ translates :title
43
+ validates_globalized_uniqueness_of :title, :scope => :locale
44
+ end
45
+
46
+ Or:
47
+
48
+ class Product < ActiveRecord::Base
49
+ translates :title
50
+ validates :title, :globalized_uniqueness => {:scope => :locale}
51
+ end
52
+
53
+ ## Todo / Known Issues
54
+
55
+ * Doesn't work yet with rails 3.0 when case_sensitive is set to false
56
+ * Might not yet work correctly with serialized attributes which are translated (haven't tested that yet)
57
+
58
+ ## Contributing
59
+
60
+ 1. Fork it
61
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
62
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
63
+ 4. Push to the branch (`git push origin my-new-feature`)
64
+ 5. Create new Pull Request
@@ -0,0 +1,18 @@
1
+ require 'bundler/setup'
2
+ require 'appraisal'
3
+ require 'rspec/core/rake_task'
4
+
5
+ require 'bundler/gem_tasks'
6
+
7
+ desc 'Default: run all tests with all supported Rails versions'
8
+ task :default => :all
9
+
10
+ desc 'Run tests with all supported Rails versions.'
11
+ task :all => ["appraisal:install"] do
12
+ exec('rake appraisal spec')
13
+ end
14
+
15
+ desc 'Run all tests'
16
+ RSpec::Core::RakeTask.new('spec') do |t|
17
+ t.pattern = FileList['spec/**/*_spec.rb']
18
+ end
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 3.0.0"
6
+
7
+ gemspec :path=>"../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 3.1.0"
6
+
7
+ gemspec :path=>"../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 3.2.0"
6
+
7
+ gemspec :path=>"../"
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'globalize3/validations/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "globalize3-validations"
8
+ spec.version = Globalize3::Validations::VERSION
9
+ spec.authors = ["Maximilian Herold"]
10
+ spec.email = ["herold@emjot.de"]
11
+ spec.description = %q{adds a uniqueness validator for globalize3 translated models}
12
+ spec.summary = %q{uniqueness validation for globalize3 translated models}
13
+ spec.homepage = "https://github.com/emjot/globalize3-validations"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_runtime_dependency "rails", "~> 3.0"
22
+ spec.add_runtime_dependency "globalize3", "~> 0.3"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.3"
25
+ spec.add_development_dependency "appraisal", "~> 0.5.1"
26
+ spec.add_development_dependency "rspec-rails", "~> 2.8.0"
27
+ spec.add_development_dependency "database_cleaner", "~> 0.6"
28
+ spec.add_development_dependency "sqlite3"
29
+ spec.add_development_dependency "rake"
30
+ end
@@ -0,0 +1,45 @@
1
+ ActiveSupport.on_load(:active_record) do
2
+
3
+ # backport 'case_sensitive_modifier' for AR 3.0.x connection adapters
4
+ if ActiveRecord::VERSION::STRING.start_with?("3.0.")
5
+
6
+ method_name = 'case_sensitive_modifier'
7
+
8
+ if defined?(ActiveRecord::ConnectionAdapters::AbstractAdapter)
9
+
10
+ abstract_adapter = ActiveRecord::ConnectionAdapters::AbstractAdapter
11
+ unless abstract_adapter.instance_methods.collect(&:to_s).include?(method_name)
12
+ abstract_adapter.class_eval do
13
+ def case_sensitive_modifier(node)
14
+ node
15
+ end
16
+ end
17
+ end
18
+
19
+ if defined?(ActiveRecord::ConnectionAdapters::MysqlAdapter)
20
+ adapter = ActiveRecord::ConnectionAdapters::MysqlAdapter
21
+ unless adapter.instance_methods.collect(&:to_s).include?(method_name)
22
+ adapter.class_eval do
23
+ def case_sensitive_modifier(node)
24
+ Arel::Nodes::Bin.new(node)
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ if defined?(ActiveRecord::ConnectionAdapters::Mysql2Adapter)
31
+ adapter = ActiveRecord::ConnectionAdapters::Mysql2Adapter
32
+ unless adapter.instance_methods.collect(&:to_s).include?(method_name)
33
+ adapter.class_eval do
34
+ def case_sensitive_modifier(node)
35
+ Arel::Nodes::Bin.new(node)
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ end
42
+
43
+ end
44
+
45
+ end
@@ -0,0 +1,135 @@
1
+ module ActiveRecord
2
+ module Validations
3
+
4
+ class GlobalizedUniquenessValidator < ActiveModel::EachValidator
5
+
6
+ def initialize(options)
7
+ super(options.reverse_merge(:case_sensitive => true))
8
+ end
9
+
10
+ # Unfortunately, we have to tie Uniqueness validators to a class.
11
+ def setup(klass)
12
+ @klass = klass
13
+ end
14
+
15
+ def validate_each(record, attribute, value)
16
+ finder_class = find_finder_class_for(record)
17
+ table = finder_class.arel_table
18
+
19
+ coder = record.class.serialized_attributes[attribute.to_s] # FIXME add/test support for serialized attributes with globalize3
20
+
21
+ # determine table / attr_column_class respecting globalize3 translations
22
+ globalized_column_class = find_globalized_column_class_for(record, attribute)
23
+ globalized = globalized_column_class.present?
24
+ if globalized
25
+ attr_column_class = globalized_column_class
26
+ table = attr_column_class.arel_table
27
+ else
28
+ attr_column_class = finder_class
29
+ end
30
+
31
+ if value && coder
32
+ value = coder.dump value
33
+ end
34
+
35
+ # build relation respecting globalize3 translations
36
+ relation = build_relation(attr_column_class, table, attribute, value)
37
+ relation = relation.and(finder_class.arel_table[finder_class.primary_key.to_sym].not_eq(record.send(:id))) if record.persisted?
38
+
39
+ Array.wrap(options[:scope]).each do |scope_item|
40
+ if globalized && ([:locale] | record.class.translated_attribute_names).include?(scope_item)
41
+ # handle globalize3 translated attribute scopes and :locale scope
42
+ scope_value = if scope_item == :locale
43
+ Globalize.locale.to_s
44
+ else
45
+ record.read_attribute(scope_item)
46
+ end
47
+ relation = relation.and(table[scope_item].eq(scope_value))
48
+ else
49
+ scope_value = record.read_attribute(scope_item)
50
+ relation = relation.and(finder_class.arel_table[scope_item].eq(scope_value))
51
+ end
52
+ end
53
+
54
+ # finalize building & execute query (respecting globalize3 translations)
55
+ scoped = finder_class.unscoped
56
+ scoped = scoped.joins(:translations) if globalized
57
+ if scoped.where(relation).exists?
58
+ record.errors.add(attribute, :taken, options.except(:case_sensitive, :scope).merge(:value => value))
59
+ end
60
+ end
61
+
62
+ protected
63
+
64
+ # The check for an existing value should be run from a class that
65
+ # isn't abstract. This means working down from the current class
66
+ # (self), to the first non-abstract class. Since classes don't know
67
+ # their subclasses, we have to build the hierarchy between self and
68
+ # the record's class.
69
+ def find_finder_class_for(record) #:nodoc:
70
+ class_hierarchy = [record.class]
71
+
72
+ while class_hierarchy.first != @klass
73
+ class_hierarchy.insert(0, class_hierarchy.first.superclass)
74
+ end
75
+
76
+ class_hierarchy.detect { |klass| !klass.abstract_class? }
77
+ end
78
+
79
+ # If the attribute of the record is globalized, returns the translation class; otherwise, returns nil.
80
+ def find_globalized_column_class_for(record, attribute)
81
+ class_hierarchy = [record.class]
82
+
83
+ while class_hierarchy.first != @klass
84
+ class_hierarchy.insert(0, class_hierarchy.first.superclass)
85
+ end
86
+
87
+ klass = class_hierarchy.detect { |klass| !klass.abstract_class? && klass.respond_to?(:translation_class) }
88
+
89
+ if klass && record.class.translated_attribute_names.include?(attribute)
90
+ klass.translation_class
91
+ else
92
+ nil
93
+ end
94
+ end
95
+
96
+ def build_relation(klass, table, attribute, value) #:nodoc:
97
+ column = klass.columns_hash[attribute.to_s]
98
+ value = column.limit ? value.to_s.mb_chars[0, column.limit] : value.to_s if value && column.text?
99
+
100
+ if !options[:case_sensitive] && value && column.text?
101
+ # will use SQL LOWER function before comparison
102
+ relation = table[attribute].lower.eq(table.lower(value))
103
+ else
104
+ value = klass.connection.case_sensitive_modifier(value)
105
+ relation = table[attribute].eq(value)
106
+ end
107
+
108
+ relation
109
+ end
110
+ end
111
+
112
+ module ClassMethods
113
+ # Validates whether the value of the specified attributes are unique across the system.
114
+ # Useful for making sure that only one user
115
+ # can be named "davidhh".
116
+ #
117
+ # See validates_uniqueness_of in ActiveRecord::Validations::ClassMethods for further explanation.
118
+ #
119
+ # This validator works the same, but additionally respects globalize3 model translations.
120
+ # Also, you can use :locale as value for :scope.
121
+ #
122
+ # For instance, if you want to validate that a product title is unique in each locale:
123
+ #
124
+ # class Product < ActiveRecord::Base
125
+ # translates :title
126
+ #
127
+ # validates_globalized_uniqueness_of :title, :scope => :locale
128
+ # end
129
+ def validates_globalized_uniqueness_of(*attr_names)
130
+ validates_with GlobalizedUniquenessValidator, _merge_attributes(attr_names)
131
+ end
132
+ end
133
+
134
+ end
135
+ end
@@ -0,0 +1,8 @@
1
+ require "globalize3/validations/version"
2
+
3
+ require "active_support"
4
+ require "active_record"
5
+ require "globalize3"
6
+
7
+ require "active_record/compatibility"
8
+ require "active_record/validations/globalized_uniqueness"
@@ -0,0 +1,5 @@
1
+ module Globalize3
2
+ module Validations
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,12 @@
1
+ class Topic < ActiveRecord::Base
2
+ has_many :replies, :dependent => :destroy, :foreign_key => "parent_id"
3
+ translates :title, :content
4
+ end
5
+
6
+ class Reply < Topic
7
+ belongs_to :topic, :foreign_key => "parent_id"
8
+ end
9
+
10
+ class Untranslated < ActiveRecord::Base
11
+ end
12
+
@@ -0,0 +1,22 @@
1
+ ActiveRecord::Migration.verbose = false
2
+
3
+ ActiveRecord::Schema.define do
4
+
5
+ create_table :untranslateds, :force => true do |t|
6
+ t.string :name
7
+ t.text :content
8
+ end
9
+
10
+ create_table :topics, :force => true do |t|
11
+ t.integer :parent_id
12
+ t.timestamps
13
+ end
14
+
15
+ create_table :topic_translations, :force => true do |t|
16
+ t.string :locale
17
+ t.references :topic
18
+ t.string :title
19
+ t.text :content
20
+ end
21
+
22
+ end
@@ -0,0 +1,37 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '../lib/globalize3-validations'))
2
+
3
+ require 'fileutils'
4
+ require 'logger'
5
+ require 'database_cleaner'
6
+
7
+ RSpec.configure do |config|
8
+
9
+ config.mock_with :rspec
10
+
11
+ config.before(:suite) do
12
+ DatabaseCleaner.strategy = :truncation
13
+
14
+ tmpdir = File.join(File.dirname(__FILE__), "../tmp")
15
+ FileUtils.mkdir(tmpdir) unless File.exist?(tmpdir)
16
+ log = File.expand_path(File.join(tmpdir, "globalize3_test.log"))
17
+ FileUtils.touch(log) unless File.exists?(log)
18
+ ActiveRecord::Base.logger = Logger.new(log)
19
+ ActiveRecord::LogSubscriber.attach_to(:active_record)
20
+
21
+ ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:')
22
+ require File.expand_path('../data/schema', __FILE__)
23
+ require File.expand_path('../data/models', __FILE__)
24
+
25
+ I18n.locale = I18n.default_locale = :en
26
+ Globalize.locale = nil
27
+ end
28
+
29
+ config.before(:each) do
30
+ DatabaseCleaner.start
31
+ end
32
+
33
+ config.after(:each) do
34
+ DatabaseCleaner.clean
35
+ end
36
+
37
+ end
@@ -0,0 +1,188 @@
1
+ # coding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe 'ActiveRecord::Validations::GlobalizedUniquenessValidator' do
5
+
6
+ before(:each) do
7
+ [Untranslated, Topic, Reply].each do |k|
8
+ k.reset_callbacks(:validate)
9
+ end
10
+ end
11
+
12
+ it "should validate uniqueness on an untranslated model" do
13
+ Untranslated.validates_globalized_uniqueness_of(:name)
14
+
15
+ u = Untranslated.new("name" => "I'm uniqué!")
16
+ u.save.should be_true
17
+
18
+ u.content = "Remaining unique"
19
+ u.save.should be_true
20
+
21
+ u2 = Untranslated.new("name" => "I'm uniqué!")
22
+ u2.valid?.should be_false
23
+ u2.errors[:name].should == ["has already been taken"]
24
+ u2.save.should be_false
25
+
26
+ u2.name = "Now Im really also unique"
27
+ u2.save.should be_true
28
+ end
29
+
30
+ it "should validate uniqueness" do
31
+ Topic.validates_globalized_uniqueness_of(:title)
32
+ title = "I'm uniqué!"
33
+
34
+ t = Topic.new("title" => title)
35
+ t.save.should be_true
36
+
37
+ t.content = "Remaining unique"
38
+ t.save.should be_true
39
+
40
+ t2 = Topic.new("title" => title)
41
+ t2.valid?.should be_false
42
+ t2.errors[:title].should == ["has already been taken"]
43
+ t2.save.should be_false
44
+
45
+ Globalize.with_locale(:de) do
46
+ t2.title = title
47
+ t2.valid?.should be_false
48
+ t2.errors[:title].should == ["has already been taken"]
49
+ t2.save.should be_false
50
+ end
51
+
52
+ t2.title = "Now Im really also unique"
53
+ t2.save.should be_true
54
+ end
55
+
56
+ it "should validate uniqueness with :locale scope" do
57
+ Topic.validates_globalized_uniqueness_of(:title, :scope => :locale)
58
+ title = "I'm uniqué!"
59
+
60
+ t = Topic.new("title" => title)
61
+ t.save.should be_true
62
+
63
+ t.content = "Remaining unique"
64
+ t.save.should be_true
65
+
66
+ t2 = Topic.new("title" => title)
67
+ t2.valid?.should be_false
68
+ t2.errors[:title].should == ["has already been taken"]
69
+ t2.save.should be_false
70
+
71
+ Globalize.with_locale(:de) do
72
+ t2.title = title
73
+ t2.valid?.should be_true
74
+ t2.save.should be_true
75
+
76
+ t3 = Topic.new("title" => title)
77
+ t3.valid?.should be_false
78
+ t3.errors[:title].should == ["has already been taken"]
79
+ end
80
+
81
+ t2.title = "Now Im really also unique"
82
+ t2.save.should be_true
83
+ end
84
+
85
+ it "should validate uniqueness with validates" do
86
+ Topic.validates :title, :globalized_uniqueness => {:scope => :locale}
87
+ Topic.create!('title' => 'abc')
88
+
89
+ t2 = Topic.new('title' => 'abc')
90
+ t2.valid?.should be_false
91
+ t2.errors[:title].should be_true
92
+ end
93
+
94
+ it "should validate uniqueness with multiple translated attributes in scope" do
95
+ Topic.validates_globalized_uniqueness_of(:content, :scope => [:locale, :title])
96
+ title = "I'm uniqué!"
97
+ content = "hello world"
98
+
99
+ t = Topic.new("title" => title, :content => content)
100
+ t.save.should be_true
101
+
102
+ t2 = Topic.new("title" => title, :content => content)
103
+ t2.valid?.should be_false
104
+ t2.errors[:content].should == ["has already been taken"]
105
+ t2.save.should be_false
106
+
107
+ Globalize.with_locale(:de) do
108
+ t2.title = title
109
+ t2.content = content
110
+ t2.valid?.should be_true
111
+ t2.save.should be_true
112
+
113
+ t3 = Topic.new("title" => title, "content" => content)
114
+ t3.valid?.should be_false
115
+ t3.errors[:content].should == ["has already been taken"]
116
+ end
117
+
118
+ t2.title = "Now Im really also unique"
119
+ t2.content = content
120
+ t2.save.should be_true
121
+
122
+ Topic.new("title" => title, :content => "foo").save.should be_true
123
+ end
124
+
125
+ it "should validate uniqueness with both translated and untranslated attributes in scope" do
126
+ Reply.validates_globalized_uniqueness_of(:content, :scope => [:locale, "parent_id"])
127
+ content = "hello world"
128
+
129
+ t = Topic.create("title" => "I'm unique!")
130
+
131
+ r1 = t.replies.create "title" => "r1", "content" => content
132
+ r1.valid?.should be_true
133
+
134
+ r2 = t.replies.create "title" => "r2", "content" => content
135
+ r2.valid?.should be_false
136
+
137
+ Globalize.with_locale(:de) do
138
+ r2.content = content
139
+ r2.save.should be_true
140
+ end
141
+
142
+ r2.content = "something else"
143
+ r2.save.should be_true
144
+
145
+ t2 = Topic.create("title" => "I'm unique too!")
146
+ r3 = t2.replies.create "title" => "r3", "content" => content
147
+ r3.valid?.should be_true
148
+ end
149
+
150
+ it "should validate case sensitive uniqueness" do
151
+ Topic.validates_globalized_uniqueness_of(:title, :case_sensitive => true, :allow_nil => true)
152
+
153
+ t = Topic.new("title" => "I'm unique!")
154
+ t.save.should be_true
155
+
156
+ t.content = "Remaining unique"
157
+ t.save.should be_true
158
+
159
+ t2 = Topic.new("title" => "I'M UNIQUE!")
160
+ t2.valid?.should be_true
161
+ t2.save.should be_true
162
+
163
+ t3 = Topic.new("title" => "I'M uNiQUe!")
164
+ t3.valid?.should be_true
165
+ t3.save.should be_true
166
+
167
+ t4 = Topic.new("title" => "I'M uNiQUe!")
168
+ t4.valid?.should be_false
169
+ t4.save.should be_false
170
+ t4.errors[:title].should == ["has already been taken"]
171
+ end
172
+
173
+ # FIXME this test fails on rails 3.0.x
174
+ it "should validate case insensitive uniqueness" do
175
+ Topic.validates_globalized_uniqueness_of(:title, :case_sensitive => false, :allow_nil => true)
176
+
177
+ t = Topic.new("title" => "I'm unique!")
178
+ t.save.should be_true
179
+
180
+ t2 = Topic.new("title" => "I'M UNIQUE!")
181
+ t2.valid?.should be_false
182
+ t2.save.should be_false
183
+ t2.errors[:title].should == ["has already been taken"]
184
+ end
185
+
186
+ it "should validate uniqueness with a translated serialized attribute"
187
+
188
+ end
metadata ADDED
@@ -0,0 +1,180 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: globalize3-validations
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Maximilian Herold
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-03-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: globalize3
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '0.3'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '0.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: appraisal
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 0.5.1
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 0.5.1
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec-rails
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: 2.8.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: 2.8.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: database_cleaner
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: '0.6'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: '0.6'
97
+ - !ruby/object:Gem::Dependency
98
+ name: sqlite3
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ! '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rake
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ! '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: adds a uniqueness validator for globalize3 translated models
126
+ email:
127
+ - herold@emjot.de
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - .gitignore
133
+ - .rspec
134
+ - .travis.yml
135
+ - Appraisals
136
+ - Gemfile
137
+ - LICENSE.txt
138
+ - README.md
139
+ - Rakefile
140
+ - gemfiles/rails_3.0.gemfile
141
+ - gemfiles/rails_3.1.gemfile
142
+ - gemfiles/rails_3.2.gemfile
143
+ - globalize3-validations.gemspec
144
+ - lib/active_record/compatibility.rb
145
+ - lib/active_record/validations/globalized_uniqueness.rb
146
+ - lib/globalize3-validations.rb
147
+ - lib/globalize3/validations/version.rb
148
+ - spec/data/models.rb
149
+ - spec/data/schema.rb
150
+ - spec/spec_helper.rb
151
+ - spec/validations/globalized_uniqueness_spec.rb
152
+ homepage: https://github.com/emjot/globalize3-validations
153
+ licenses:
154
+ - MIT
155
+ metadata: {}
156
+ post_install_message:
157
+ rdoc_options: []
158
+ require_paths:
159
+ - lib
160
+ required_ruby_version: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - ! '>='
163
+ - !ruby/object:Gem::Version
164
+ version: '0'
165
+ required_rubygems_version: !ruby/object:Gem::Requirement
166
+ requirements:
167
+ - - ! '>='
168
+ - !ruby/object:Gem::Version
169
+ version: '0'
170
+ requirements: []
171
+ rubyforge_project:
172
+ rubygems_version: 2.0.3
173
+ signing_key:
174
+ specification_version: 4
175
+ summary: uniqueness validation for globalize3 translated models
176
+ test_files:
177
+ - spec/data/models.rb
178
+ - spec/data/schema.rb
179
+ - spec/spec_helper.rb
180
+ - spec/validations/globalized_uniqueness_spec.rb