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 +4 -4
- data/Gemfile +1 -1
- data/README.md +0 -4
- data/lib/rom-rails.rb +2 -3
- data/lib/rom/rails/model/form.rb +2 -0
- data/lib/rom/rails/version.rb +1 -1
- data/rom-rails.gemspec +2 -1
- data/spec/dummy/lib/rom/test_adapter.rb +1 -0
- metadata +24 -14
- data/lib/rom/model.rb +0 -14
- data/lib/rom/rails/model/attributes.rb +0 -133
- data/lib/rom/rails/model/validator.rb +0 -191
- data/lib/rom/rails/model/validator/uniqueness_validator.rb +0 -83
- data/spec/integration/user_attributes_spec.rb +0 -48
- data/spec/unit/validator/embedded_spec.rb +0 -118
- data/spec/unit/validator_spec.rb +0 -163
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2a0fecb21539dab24cc3b9dc09fd911b1be12a9d
|
|
4
|
+
data.tar.gz: 8aebc8697715bb34f06a4e4a71af39d4d90b56fc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1df2b00473fbeeddfbc89a8f86464f0b3a1bce5f129b89ef21be1ebc453459835a32a13e1dfffabec190c39bb46bc6da22f8b7b30412288236bfbe3384a6f66a
|
|
7
|
+
data.tar.gz: 7170c0882c07630adfce78a90b2f3268625f425ad179fb44fe4a8983933fca4adea37787ee1b474047699602f1712fe5c185ed639fda4d01ee1e853ae5ccc6b6
|
data/Gemfile
CHANGED
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
data/lib/rom/rails/model/form.rb
CHANGED
data/lib/rom/rails/version.rb
CHANGED
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.
|
|
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'
|
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.
|
|
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-
|
|
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.
|
|
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.
|
|
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
|
data/spec/unit/validator_spec.rb
DELETED
|
@@ -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
|