rom-rails 0.5.0.beta1 → 0.5.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e97b52065b6d47076303cb3e7b01bf0b2b26b2d2
4
- data.tar.gz: 3a20e700c19316431532ea0780e176597e964a04
3
+ metadata.gz: 2a0fecb21539dab24cc3b9dc09fd911b1be12a9d
4
+ data.tar.gz: 8aebc8697715bb34f06a4e4a71af39d4d90b56fc
5
5
  SHA512:
6
- metadata.gz: cf5e13ef79c24653c6fb3a83b93de8a01c11a3f9883b7f2dfb1cf0a6030a95bced0b82432d62c174bc05c48f1ef416fce6a50653d80005fee31e2a7c335741d7
7
- data.tar.gz: 2b939dbc62be89dbaee3e7e9ccafcaa8f93e036b61ad3d9820024d374a8e8fb4e0a75b958c9eef37f93ffc6309daf5cb63c1e341e92bcc4f13866c2830a95a26
6
+ metadata.gz: 1df2b00473fbeeddfbc89a8f86464f0b3a1bce5f129b89ef21be1ebc453459835a32a13e1dfffabec190c39bb46bc6da22f8b7b30412288236bfbe3384a6f66a
7
+ data.tar.gz: 7170c0882c07630adfce78a90b2f3268625f425ad179fb44fe4a8983933fca4adea37787ee1b474047699602f1712fe5c185ed639fda4d01ee1e853ae5ccc6b6
data/Gemfile CHANGED
@@ -4,7 +4,7 @@ gemspec
4
4
 
5
5
  RAILS_VERSION = '4.2.1'
6
6
 
7
- %w(railties activemodel actionview actionpack activerecord).each do |name|
7
+ %w(railties actionview actionpack activerecord).each do |name|
8
8
  gem name, RAILS_VERSION
9
9
  end
10
10
 
data/README.md CHANGED
@@ -30,10 +30,6 @@ To run tests:
30
30
  RAILS_ENV=test bundle exec rake db:migrate
31
31
  bundle exec rake
32
32
 
33
- ## Issues
34
-
35
- Please report any issues in the main [rom-rb/rom](https://github.com/rom-rb/rom/issues) issue tracker.
36
-
37
33
  ## Resources
38
34
 
39
35
  You can read more about ROM and Rails on the official website:
data/lib/rom-rails.rb CHANGED
@@ -1,6 +1,5 @@
1
- require 'active_model'
2
-
3
1
  require 'rom'
2
+
4
3
  require 'rom/rails/version'
5
4
  require 'rom/rails/railtie'
6
- require 'rom/model'
5
+ require 'rom/rails/model/form'
@@ -1,3 +1,5 @@
1
+ require 'rom-model'
2
+
1
3
  require 'rom/rails/model/form/class_interface'
2
4
  require 'rom/rails/model/form/error_proxy'
3
5
 
@@ -1,5 +1,5 @@
1
1
  module ROM
2
2
  module Rails
3
- VERSION = '0.5.0.beta1'.freeze
3
+ VERSION = '0.5.0.rc1'.freeze
4
4
  end
5
5
  end
data/rom-rails.gemspec CHANGED
@@ -17,7 +17,8 @@ Gem::Specification.new do |spec|
17
17
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
18
  spec.require_paths = ["lib"]
19
19
 
20
- spec.add_runtime_dependency 'rom', '~> 0.9.0.beta1'
20
+ spec.add_runtime_dependency 'rom', '~> 0.9.0.rc1'
21
+ spec.add_runtime_dependency 'rom-model', '~> 0.1', '>= 0.1.0'
21
22
  spec.add_runtime_dependency 'addressable', '~> 2.3'
22
23
  spec.add_runtime_dependency 'charlatan', '~> 0.1'
23
24
  spec.add_runtime_dependency 'virtus', '~> 1.0', '>= 1.0.5'
@@ -1,6 +1,7 @@
1
1
  module ROM
2
2
  module TestAdapter
3
3
  class Relation < ROM::Relation
4
+ adapter :test_adapter
4
5
  end
5
6
 
6
7
  class Gateway < ROM::Gateway
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rom-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0.beta1
4
+ version: 0.5.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Solnica
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-10 00:00:00.000000000 Z
11
+ date: 2015-08-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rom
@@ -16,14 +16,34 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.9.0.beta1
19
+ version: 0.9.0.rc1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.9.0.beta1
26
+ version: 0.9.0.rc1
27
+ - !ruby/object:Gem::Dependency
28
+ name: rom-model
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.1'
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: 0.1.0
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "~>"
42
+ - !ruby/object:Gem::Version
43
+ version: '0.1'
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 0.1.0
27
47
  - !ruby/object:Gem::Dependency
28
48
  name: addressable
29
49
  requirement: !ruby/object:Gem::Requirement
@@ -164,17 +184,13 @@ files:
164
184
  - lib/generators/rom/relation/templates/relation.rb.erb
165
185
  - lib/generators/rom/relation_generator.rb
166
186
  - lib/rom-rails.rb
167
- - lib/rom/model.rb
168
187
  - lib/rom/rails/active_record/configuration.rb
169
188
  - lib/rom/rails/configuration.rb
170
189
  - lib/rom/rails/controller_extension.rb
171
190
  - lib/rom/rails/inflections.rb
172
- - lib/rom/rails/model/attributes.rb
173
191
  - lib/rom/rails/model/form.rb
174
192
  - lib/rom/rails/model/form/class_interface.rb
175
193
  - lib/rom/rails/model/form/error_proxy.rb
176
- - lib/rom/rails/model/validator.rb
177
- - lib/rom/rails/model/validator/uniqueness_validator.rb
178
194
  - lib/rom/rails/railtie.rb
179
195
  - lib/rom/rails/tasks/db.rake
180
196
  - lib/rom/rails/version.rb
@@ -243,7 +259,6 @@ files:
243
259
  - spec/integration/initializer_spec.rb
244
260
  - spec/integration/logger_spec.rb
245
261
  - spec/integration/new_user_form_spec.rb
246
- - spec/integration/user_attributes_spec.rb
247
262
  - spec/integration/user_commands_spec.rb
248
263
  - spec/integration/user_model_mapping_spec.rb
249
264
  - spec/lib/active_record/configuration_spec.rb
@@ -253,8 +268,6 @@ files:
253
268
  - spec/lib/generators/relation_generator_spec.rb
254
269
  - spec/spec_helper.rb
255
270
  - spec/unit/form_spec.rb
256
- - spec/unit/validator/embedded_spec.rb
257
- - spec/unit/validator_spec.rb
258
271
  homepage: http://rom-rb.org
259
272
  licenses:
260
273
  - MIT
@@ -344,7 +357,6 @@ test_files:
344
357
  - spec/integration/initializer_spec.rb
345
358
  - spec/integration/logger_spec.rb
346
359
  - spec/integration/new_user_form_spec.rb
347
- - spec/integration/user_attributes_spec.rb
348
360
  - spec/integration/user_commands_spec.rb
349
361
  - spec/integration/user_model_mapping_spec.rb
350
362
  - spec/lib/active_record/configuration_spec.rb
@@ -354,5 +366,3 @@ test_files:
354
366
  - spec/lib/generators/relation_generator_spec.rb
355
367
  - spec/spec_helper.rb
356
368
  - spec/unit/form_spec.rb
357
- - spec/unit/validator/embedded_spec.rb
358
- - spec/unit/validator_spec.rb
data/lib/rom/model.rb DELETED
@@ -1,14 +0,0 @@
1
- require 'charlatan'
2
-
3
- module ROM
4
- module Model
5
- class ValidationError < CommandError
6
- include Charlatan.new(:errors)
7
- include Equalizer.new(:errors)
8
- end
9
- end
10
- end
11
-
12
- require 'rom/rails/model/attributes'
13
- require 'rom/rails/model/validator'
14
- require 'rom/rails/model/form'
@@ -1,133 +0,0 @@
1
- require 'virtus'
2
- require 'active_model/conversion'
3
-
4
- module ROM
5
- module Model
6
- # Mixin for validatable and coercible parameters
7
- #
8
- # @example
9
- #
10
- # class UserAttributes
11
- # include ROM::Model::Attributes
12
- #
13
- # attribute :email, String
14
- # attribute :age, Integer
15
- #
16
- # validates :email, :age, presence: true
17
- # end
18
- #
19
- # user_attrs = UserAttributes.new(email: '', age: '18')
20
- #
21
- # user_attrs.email # => ''
22
- # user_attrs.age # => 18
23
- #
24
- # user_attrs.valid? # => false
25
- # user_attrs.errors # => #<ActiveModel::Errors:0x007fd2423fadb0 ...>
26
- #
27
- # @api public
28
- module Attributes
29
- VirtusModel = Virtus.model(nullify_blank: true)
30
-
31
- # Inclusion hook used to extend a class with required interfaces
32
- #
33
- # @api private
34
- def self.included(base)
35
- base.class_eval do
36
- include VirtusModel
37
- include ActiveModel::Conversion
38
- end
39
- base.extend(ClassMethods)
40
- end
41
-
42
- # Return model name for the attributes class
43
- #
44
- # The model name object is configurable using `set_model_name` macro
45
- #
46
- # @see ClassMethods#set_model_name
47
- #
48
- # @return [ActiveModel::Name]
49
- #
50
- # @api public
51
- def model_name
52
- self.class.model_name
53
- end
54
-
55
- # Class extensions for an attributes class
56
- #
57
- # @api public
58
- module ClassMethods
59
- # Default timestamp attribute names used by `timestamps` method
60
- DEFAULT_TIMESTAMPS = [:created_at, :updated_at].freeze
61
-
62
- # Process input and return attributes instance
63
- #
64
- # @example
65
- # class UserAttributes
66
- # include ROM::Model::Attributes
67
- #
68
- # attribute :name, String
69
- # end
70
- #
71
- # UserAttributes[name: 'Jane']
72
- #
73
- # @param [Hash,#to_hash] input The input params
74
- #
75
- # @return [Attributes]
76
- #
77
- # @api public
78
- def [](input)
79
- input.is_a?(self) ? input : new(input)
80
- end
81
-
82
- # Macro for defining ActiveModel::Name object on the attributes class
83
- #
84
- # This is essential for rails helpers to work properly when generating
85
- # form input names etc.
86
- #
87
- # @example
88
- # class UserAttributes
89
- # include ROM::Model::Attributes
90
- #
91
- # set_model_name 'User'
92
- # end
93
- #
94
- # @return [undefined]
95
- #
96
- # @api public
97
- def set_model_name(name)
98
- class_eval <<-RUBY
99
- def self.model_name
100
- @model_name ||= ActiveModel::Name.new(self, nil, #{name.inspect})
101
- end
102
- RUBY
103
- end
104
-
105
- # Shortcut for defining timestamp attributes like created_at etc.
106
- #
107
- # @example
108
- # class NewPostAttributes
109
- # include ROM::Model::Attributes
110
- #
111
- # # provide name(s) explicitly
112
- # timestamps :published_at
113
- #
114
- # # defaults to :created_at, :updated_at without args
115
- # timestamps
116
- # end
117
- #
118
- # @api public
119
- def timestamps(*attrs)
120
- if attrs.empty?
121
- DEFAULT_TIMESTAMPS.each do |t|
122
- attribute t, DateTime, default: proc { DateTime.now }
123
- end
124
- else
125
- attrs.each do |attr|
126
- attribute attr, DateTime, default: proc { DateTime.now }
127
- end
128
- end
129
- end
130
- end
131
- end
132
- end
133
- end
@@ -1,191 +0,0 @@
1
- require 'rom/rails/model/validator/uniqueness_validator'
2
- require 'rom/support/class_macros'
3
-
4
- module ROM
5
- module Model
6
- # Mixin for ROM-compliant validator objects
7
- #
8
- # @example
9
- #
10
- #
11
- # class UserAttributes
12
- # include ROM::Model::Attributes
13
- #
14
- # attribute :name
15
- #
16
- # validates :name, presence: true
17
- # end
18
- #
19
- # class UserValidator
20
- # include ROM::Model::Validator
21
- # end
22
- #
23
- # attrs = UserAttributes.new(name: '')
24
- # UserValidator.call(attrs) # raises ValidationError
25
- #
26
- # @api public
27
- module Validator
28
- # Inclusion hook that extends a class with required interfaces
29
- #
30
- # @api private
31
- def self.included(base)
32
- base.class_eval do
33
- extend ClassMethods
34
- extend ROM::ClassMacros
35
-
36
- include ActiveModel::Validations
37
- include Equalizer.new(:attributes, :errors)
38
-
39
- base.defines :embedded_validators
40
-
41
- embedded_validators({})
42
- end
43
- end
44
-
45
- # @return [Model::Attributes]
46
- #
47
- # @api private
48
- attr_reader :attributes
49
-
50
- # @api private
51
- attr_reader :attr_names
52
-
53
- delegate :model_name, to: :attributes
54
-
55
- # @api private
56
- def initialize(attributes)
57
- @attributes = attributes
58
- @attr_names = self.class.validators.map(&:attributes).flatten.uniq
59
- end
60
-
61
- # @return [Model::Attributes]
62
- #
63
- # @api public
64
- def to_model
65
- attributes
66
- end
67
-
68
- # Trigger validations and return attributes on success
69
- #
70
- # @raises ValidationError
71
- #
72
- # @return [Model::Attributes]
73
- #
74
- # @api public
75
- def call
76
- raise ValidationError, errors unless valid?
77
- attributes
78
- end
79
-
80
- private
81
-
82
- # This is needed for ActiveModel::Validations to work properly
83
- # as it expects the object to provide attribute values. Meh.
84
- #
85
- # @api private
86
- def method_missing(name, *args, &block)
87
- if attr_names.include?(name)
88
- attributes[name]
89
- else
90
- super
91
- end
92
- end
93
-
94
- module ClassMethods
95
- # Set relation name for a validator
96
- #
97
- # This is needed for validators that require database access
98
- #
99
- # @example
100
- #
101
- # class UserValidator
102
- # include ROM::Model::Validator
103
- #
104
- # relation :users
105
- #
106
- # validates :name, uniqueness: true
107
- # end
108
- #
109
- # @return [Symbol]
110
- #
111
- # @api public
112
- def relation(name = nil)
113
- @relation = name if name
114
- @relation
115
- end
116
-
117
- # @api private
118
- def set_model_name(name)
119
- class_eval <<-RUBY
120
- def self.model_name
121
- @model_name ||= ActiveModel::Name.new(self, nil, #{name.inspect})
122
- end
123
- RUBY
124
- end
125
-
126
- # Trigger validation for specific attributes
127
- #
128
- # @param [Model::Attributes] attributes The attributes for validation
129
- #
130
- # @raises [ValidationError]
131
- #
132
- # @return [Model::Attributes]
133
- def call(attributes)
134
- validator = new(attributes)
135
- validator.call
136
- end
137
-
138
- # Specify an embedded validator for nested structures
139
- #
140
- # @example
141
- # class UserValidator
142
- # include ROM::Model::Validator
143
- #
144
- # set_model_name 'User'
145
- #
146
- # embedded :address do
147
- # validates :city, :street, :zipcode, presence: true
148
- # end
149
- #
150
- # emebdded :tasks do
151
- # validates :title, presence: true
152
- # end
153
- # end
154
- #
155
- # validator = UserAttributes.new(address: {}, tasks: {})
156
- #
157
- # validator.valid? # false
158
- # validator.errors[:address].first # errors for address
159
- # validator.errors[:tasks] # errors for tasks
160
- #
161
- # @api public
162
- def embedded(name, &block)
163
- validator_class = Class.new { include ROM::Model::Validator }
164
- validator_class.class_eval(&block)
165
- validator_class.set_model_name(name.to_s.classify)
166
-
167
- embedded_validators[name] = validator_class
168
-
169
- validates name, presence: true
170
-
171
- validate do
172
- value = attributes[name]
173
-
174
- if value.present?
175
- Array([value]).flatten.each do |object|
176
- validator = validator_class.new(object)
177
- validator.validate
178
-
179
- if validator.errors.any?
180
- errors.add(name, validator.errors)
181
- else
182
- errors.add(name, [])
183
- end
184
- end
185
- end
186
- end
187
- end
188
- end
189
- end
190
- end
191
- end
@@ -1,83 +0,0 @@
1
- require 'active_model/validator'
2
-
3
- module ROM
4
- module Model
5
- module Validator
6
- # Uniqueness validation
7
- #
8
- # @api public
9
- class UniquenessValidator < ActiveModel::EachValidator
10
- # Relation validator class
11
- #
12
- # @api private
13
- attr_reader :klass
14
-
15
- # error message
16
- #
17
- # @return [String, Symbol]
18
- #
19
- # @api private
20
- attr_reader :message
21
-
22
- # @api private
23
- def initialize(options)
24
- super
25
- @klass = options.fetch(:class)
26
- @message = options.fetch(:message) { :taken }
27
- @scope_keys = options[:scope]
28
- end
29
-
30
- # Hook called by ActiveModel internally
31
- #
32
- # @api private
33
- def validate_each(validator, name, value)
34
- scope = Array(@scope_keys).each_with_object({}) do |key, scope|
35
- scope[key] = validator.to_model[key]
36
- end
37
- validator.errors.add(name, message) unless unique?(name, value, scope)
38
- end
39
-
40
- private
41
-
42
- # Get relation object from the rom env
43
- #
44
- # @api private
45
- def relation
46
- if relation_name
47
- rom.relations[relation_name]
48
- else
49
- raise "relation must be specified to use uniqueness validation"
50
- end
51
- end
52
-
53
- # Relation name defined on the validator class
54
- #
55
- # @api private
56
- def relation_name
57
- klass.relation
58
- end
59
-
60
- # Shortcut to access global rom env
61
- #
62
- # @return [ROM::Env]
63
- #
64
- # @api private
65
- def rom
66
- ROM.env
67
- end
68
-
69
- # Ask relation if a given attribute value is unique
70
- #
71
- # This uses `Relation#unique?` interface that not all adapters can
72
- # implement.
73
- #
74
- # @return [TrueClass,FalseClass]
75
- #
76
- # @api private
77
- def unique?(name, value, scope)
78
- relation.unique?({name => value}.merge(scope))
79
- end
80
- end
81
- end
82
- end
83
- end
@@ -1,48 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe ROM::Model::Attributes do
4
- let(:attributes) do
5
- Class.new do
6
- include ROM::Model::Attributes
7
-
8
- attribute :name, String
9
-
10
- timestamps
11
- end
12
- end
13
-
14
- describe '.timestamps' do
15
- it 'provides a way to specify timestamps with default values' do
16
- expect(attributes.new.created_at).to be_a(DateTime)
17
- expect(attributes.new.updated_at).to be_a(DateTime)
18
- end
19
-
20
- context 'passing in arbritrary names' do
21
- it 'excludes :created_at when passing in :updated_at' do
22
- attributes = Class.new {
23
- include ROM::Model::Attributes
24
-
25
- timestamps(:updated_at)
26
- }
27
-
28
- model = attributes.new
29
-
30
- expect(model).not_to respond_to(:created_at)
31
- expect(model).to respond_to(:updated_at)
32
- end
33
-
34
- it 'accepts multiple timestamp attribute names' do
35
- attributes = Class.new {
36
- include ROM::Model::Attributes
37
-
38
- timestamps(:published_at, :revised_at)
39
- }
40
-
41
- model = attributes.new
42
-
43
- expect(model).to respond_to(:published_at)
44
- expect(model).to respond_to(:revised_at)
45
- end
46
- end
47
- end
48
- end
@@ -1,118 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe 'Embedded validators' do
4
- it 'allows defining a validator for a nested hash' do
5
- user_validator = Class.new do
6
- include ROM::Model::Validator
7
-
8
- set_model_name 'User'
9
-
10
- validates :name, presence: true
11
-
12
- embedded :address do
13
- set_model_name 'Address'
14
-
15
- validates :street, :city, :zipcode, presence: true
16
- end
17
- end
18
-
19
- attributes = { name: '', address: { street: '', city: '', zipcode: '' } }
20
-
21
- expect { user_validator.call(attributes) }.to raise_error(
22
- ROM::Model::ValidationError)
23
-
24
- validator = user_validator.new(attributes)
25
-
26
- expect(validator).to_not be_valid
27
-
28
- expect(validator.errors[:name]).to include("can't be blank")
29
-
30
- address_errors = validator.errors[:address].first
31
-
32
- expect(address_errors).to_not be_empty
33
-
34
- expect(address_errors[:street]).to include("can't be blank")
35
- expect(address_errors[:city]).to include("can't be blank")
36
- expect(address_errors[:zipcode]).to include("can't be blank")
37
- end
38
-
39
- it 'allows defining a validator for a nested array' do
40
- user_validator = Class.new do
41
- include ROM::Model::Validator
42
-
43
- set_model_name 'User'
44
-
45
- validates :name, presence: true
46
-
47
- embedded :tasks do
48
- set_model_name 'Task'
49
-
50
- validates :title, presence: true
51
- end
52
- end
53
-
54
- attributes = {
55
- name: '',
56
- tasks: [
57
- { title: '' },
58
- { title: 'Two' }
59
- ]
60
- }
61
-
62
- expect { user_validator.call(attributes) }.to raise_error(
63
- ROM::Model::ValidationError)
64
-
65
- validator = user_validator.new(attributes)
66
-
67
- expect(validator).to_not be_valid
68
-
69
- expect(validator.errors[:name]).to include("can't be blank")
70
-
71
- task_errors = validator.errors[:tasks]
72
-
73
- expect(task_errors).to_not be_empty
74
-
75
- expect(task_errors[0][:title]).to include("can't be blank")
76
- expect(task_errors[1]).to be_empty
77
- end
78
-
79
- it 'validates presence of the nested structure' do
80
- user_validator = Class.new do
81
- include ROM::Model::Validator
82
-
83
- set_model_name 'User'
84
-
85
- validates :name, presence: true
86
-
87
- embedded :tasks do
88
- set_model_name 'Task'
89
-
90
- validates :title, presence: true
91
- end
92
- end
93
-
94
- validator = user_validator.new(name: '')
95
- validator.validate
96
-
97
- expect(validator.errors[:name]).to include("can't be blank")
98
- expect(validator.errors[:tasks]).to include("can't be blank")
99
- end
100
-
101
- it 'exposes registered validators in embedded_validators hash' do
102
- user_validator = Class.new do
103
- include ROM::Model::Validator
104
-
105
- set_model_name 'User'
106
-
107
- validates :name, presence: true
108
-
109
- embedded :tasks do
110
- set_model_name 'Task'
111
-
112
- validates :title, presence: true
113
- end
114
- end
115
-
116
- expect(user_validator.embedded_validators[:tasks]).to be_present
117
- end
118
- end
@@ -1,163 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe 'Validation' do
4
- subject(:validator) { user_validator.new(attributes) }
5
-
6
- let(:user_attrs) do
7
- Class.new {
8
- include ROM::Model::Attributes
9
-
10
- set_model_name 'User'
11
-
12
- attribute :name, String
13
- attribute :email, String
14
- attribute :birthday, Date
15
- }
16
- end
17
-
18
- let(:user_validator) do
19
- Class.new {
20
- include ROM::Model::Validator
21
-
22
- relation :users
23
-
24
- validates :name, presence: true, uniqueness: { message: 'TAKEN!' }
25
- validates :email, uniqueness: true
26
-
27
- def self.name
28
- 'User'
29
- end
30
- }
31
- end
32
-
33
- describe '#call' do
34
- let(:attributes) { user_attrs.new }
35
-
36
- it 'raises validation error when attributes are not valid' do
37
- expect { validator.call }.to raise_error(ROM::Model::ValidationError)
38
- end
39
- end
40
-
41
- describe "#validate" do
42
- let(:attributes) { user_attrs.new }
43
-
44
- it "sets errors when attributes are not valid" do
45
- validator.validate
46
- expect(validator.errors[:name]).to eql(["can't be blank"])
47
- end
48
- end
49
-
50
- describe ':presence' do
51
- let(:attributes) { user_attrs.new(name: '') }
52
-
53
- it 'sets error messages' do
54
- expect(validator).to_not be_valid
55
- expect(validator.errors[:name]).to eql(["can't be blank"])
56
- end
57
- end
58
-
59
- describe ':uniqueness' do
60
- let(:attributes) { user_attrs.new(name: 'Jane', email: 'jane@doe.org') }
61
-
62
- it 'sets default error messages' do
63
- rom.relations.users.insert(name: 'Jane', email: 'jane@doe.org')
64
-
65
- expect(validator).to_not be_valid
66
- expect(validator.errors[:email]).to eql(['has already been taken'])
67
- end
68
-
69
- it 'sets custom error messages' do
70
- rom.relations.users.insert(name: 'Jane', email: 'jane@doe.org')
71
-
72
- expect(validator).to_not be_valid
73
- expect(validator.errors[:name]).to eql(['TAKEN!'])
74
- end
75
-
76
- context 'with unique attributes within a scope' do
77
- let(:user_validator) do
78
- Class.new {
79
- include ROM::Model::Validator
80
-
81
- relation :users
82
-
83
- validates :email, uniqueness: {scope: :name}
84
-
85
- def self.name
86
- 'User'
87
- end
88
- }
89
- end
90
-
91
- let(:doubly_scoped_validator) do
92
- Class.new {
93
- include ROM::Model::Validator
94
-
95
- relation :users
96
-
97
- validates :email, uniqueness: {scope: [:name, :birthday]}
98
-
99
- def self.name
100
- 'User'
101
- end
102
- }
103
- end
104
-
105
- it 'does not add errors' do
106
- rom.relations.users.insert(name: 'Jane', email: 'jane+doe@doe.org')
107
- attributes = user_attrs.new(name: 'Jane', email: 'jane@doe.org', birthday: Date.parse('2014-12-12'))
108
- validator = user_validator.new(attributes)
109
- expect(validator).to be_valid
110
- end
111
-
112
- it 'adds an error when the doubly scoped validation fails' do
113
- attributes = user_attrs.new(name: 'Jane', email: 'jane@doe.org', birthday: Date.parse('2014-12-12'))
114
- validator = doubly_scoped_validator.new(attributes)
115
- expect(validator).to be_valid
116
-
117
- rom.relations.users.insert(attributes.attributes)
118
- expect(validator).to_not be_valid
119
-
120
- attributes = user_attrs.new(name: 'Jane', email: 'jane+doe@doe.org', birthday: Date.parse('2014-12-12'))
121
- validator = doubly_scoped_validator.new(attributes)
122
- expect(validator).to be_valid
123
- end
124
- end
125
-
126
- describe 'with missing relation' do
127
- let(:user_validator) do
128
- Class.new {
129
- include ROM::Model::Validator
130
-
131
- validates :email, uniqueness: true
132
-
133
- def self.name
134
- 'User'
135
- end
136
- }
137
- end
138
-
139
- it 'raises a helpful error' do
140
- validator = user_validator.new(user_attrs.new)
141
- expect {
142
- validator.valid?
143
- }.to raise_error(/relation must be specified/)
144
- end
145
- end
146
- end
147
-
148
- describe '#method_missing' do
149
- let(:attributes) { { name: 'Jane' } }
150
-
151
- it 'returns attribute value if present' do
152
- expect(validator.name).to eql('Jane')
153
- end
154
-
155
- it 'returns nil if attribute is not present' do
156
- expect(validator.email).to be(nil)
157
- end
158
-
159
- it 'raises error when name does not match any of the attributes' do
160
- expect { validator.foobar }.to raise_error(NoMethodError, /foobar/)
161
- end
162
- end
163
- end