rom-rails 0.5.0.beta1 → 0.5.0.rc1

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.
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