Skip to content

Commit

Permalink
Support ActiveModel 4.0, which unfortunately does not send :class an …
Browse files Browse the repository at this point in the history
…an option to the validator’s constructor.
  • Loading branch information
wvanbergen committed Oct 15, 2014
1 parent 307547e commit 15e52dc
Show file tree
Hide file tree
Showing 8 changed files with 31 additions and 18 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
.bundle
.config
.yardoc
Gemfile.lock
Gemfile*.lock
InstalledFiles
_yardoc
coverage
Expand Down
4 changes: 4 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,9 @@ rvm:
- 2.0.0
- 2.1.3

gemfile:
- Gemfile.activerecord40
- Gemfile.activerecord41

before_script:
- mysql -e 'create database database_validations;'
4 changes: 4 additions & 0 deletions Gemfile.activerecord40
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
source 'https://rubygems.org'
gemspec

gem 'activerecord', '~> 4.0.0'
4 changes: 4 additions & 0 deletions Gemfile.activerecord41
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
source 'https://rubygems.org'
gemspec

gem 'activerecord', '~> 4.1.0'
4 changes: 2 additions & 2 deletions activerecord-databasevalidations.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ Gem::Specification.new do |spec|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.require_paths = ["lib"]

spec.add_runtime_dependency "activerecord", "~> 4"
spec.add_runtime_dependency "activerecord", "~> 4.0"

spec.add_development_dependency "bundler", "~> 1.5"
spec.add_development_dependency "rake"
spec.add_development_dependency "minitest", "~> 5"
spec.add_development_dependency "minitest"
spec.add_development_dependency "mysql2"
end
19 changes: 9 additions & 10 deletions lib/active_record/validations/database_constraints.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,11 @@ class DatabaseConstraintsValidator < ActiveModel::EachValidator
longblob: { validator: ActiveModel::Validations::BytesizeValidator, default_maximum: 2 ** 32 - 1 },
}

attr_reader :klass, :constraints
attr_reader :constraints

VALID_CONSTRAINTS = Set[:size, :basic_multilingual_plane, :not_null]

def initialize(options = {})
@klass = options[:class]
@constraints = Set.new(Array.wrap(options[:in]) + Array.wrap(options[:with]))
@constraint_validators = {}
super
Expand All @@ -39,14 +38,14 @@ def check_validity!
raise ArgumentError, "#{invalid_constraints.map(&:inspect).join(',')} is not a valid constraint." unless invalid_constraints.empty?
end

def not_null_validator(column)
def not_null_validator(klass, column)
return unless constraints.include?(:not_null)
return if column.null

ActiveModel::Validations::NotNullValidator.new(attributes: [column.name.to_sym], class: klass)
end

def size_validator(column)
def size_validator(klass, column)
return unless constraints.include?(:size)
return unless column.text? || column.binary?

Expand All @@ -61,26 +60,26 @@ def size_validator(column)
end
end

def basic_multilingual_plane_validator(column)
def basic_multilingual_plane_validator(klass, column)
return unless constraints.include?(:basic_multilingual_plane)
return unless column.text? && column.collation =~ /\Autf8(?:mb3)?_/
ActiveModel::Validations::BasicMultilingualPlaneValidator.new(attributes: [column.name.to_sym], class: klass)
end

def attribute_validators(attribute)
def attribute_validators(klass, attribute)
@constraint_validators[attribute] ||= begin
column = klass.columns_hash[attribute.to_s] or raise ArgumentError.new("Model #{self.class.name} does not have column #{column_name}!")

[
not_null_validator(column),
size_validator(column),
basic_multilingual_plane_validator(column),
not_null_validator(klass, column),
size_validator(klass, column),
basic_multilingual_plane_validator(klass, column),
].compact
end
end

def validate_each(record, attribute, value)
attribute_validators(attribute).each do |validator|
attribute_validators(record.class, attribute).each do |validator|
validator.validate_each(record, attribute, value)
end
end
Expand Down
10 changes: 5 additions & 5 deletions test/database_constraints_validator_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,22 +49,22 @@ def test_validators_are_defined

def test_not_null_field_defines_not_null_validator_if_requested
validator = Foo._validators[:checked].first
subvalidators = validator.attribute_validators(:checked)
subvalidators = validator.attribute_validators(Foo, :checked)
assert_equal 1, subvalidators.length
assert_kind_of ActiveModel::Validations::NotNullValidator, subvalidators.first
end

def test_string_field_defines_length_validator_by_default
validator = Foo._validators[:string].first
subvalidators = validator.attribute_validators(:string)
subvalidators = validator.attribute_validators(Foo, :string)
assert_equal 1, subvalidators.length
assert_kind_of ActiveModel::Validations::LengthValidator, subvalidators.first
assert_equal 40, subvalidators.first.options[:maximum]
end

def test_blob_field_defines_bytesize_validator
validator = Foo._validators[:blob].first
subvalidators = validator.attribute_validators(:blob)
subvalidators = validator.attribute_validators(Foo, :blob)
assert_equal 1, subvalidators.length
assert_kind_of ActiveModel::Validations::BytesizeValidator, subvalidators.first
assert_equal 65535, subvalidators.first.options[:maximum]
Expand All @@ -73,7 +73,7 @@ def test_blob_field_defines_bytesize_validator

def test_not_null_text_field_defines_requested_bytesize_validator_and_unicode_validator
validator = Foo._validators[:not_null_text].first
subvalidators = validator.attribute_validators(:not_null_text)
subvalidators = validator.attribute_validators(Foo, :not_null_text)
assert_equal 2, subvalidators.length

assert_kind_of ActiveModel::Validations::BytesizeValidator, subvalidators.first
Expand All @@ -90,7 +90,7 @@ def test_not_null_columns_with_a_default_value

def test_should_not_create_a_validor_for_a_utf8mb4_field
assert Bar.new(mb4_string: '💩').valid?
Bar._validators[:mb4_string].first.attribute_validators(:mb4_string).empty?
Bar._validators[:mb4_string].first.attribute_validators(Bar, :mb4_string).empty?
end

def test_error_messages
Expand Down
2 changes: 2 additions & 0 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

require "active_record/database_validations"

Minitest::Test = MiniTest::Unit::TestCase unless defined?(MiniTest::Test)

database_yml = YAML.load_file(File.expand_path('../database.yml', __FILE__))
ActiveRecord::Base.establish_connection(database_yml['test'])
I18n.enforce_available_locales = false

0 comments on commit 15e52dc

Please sign in to comment.