rom-rails 0.3.3 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +19 -0
- data/lib/generators/rom/relation/templates/relation.rb.erb +3 -3
- data/lib/generators/rom/relation_generator.rb +5 -5
- data/lib/rom/rails/active_record/configuration.rb +1 -1
- data/lib/rom/rails/configuration.rb +6 -1
- data/lib/rom/rails/inflections.rb +2 -1
- data/lib/rom/rails/model/form/class_interface.rb +2 -2
- data/lib/rom/rails/model/validator.rb +75 -5
- data/lib/rom/rails/model/validator/uniqueness_validator.rb +7 -3
- data/lib/rom/rails/railtie.rb +68 -64
- data/lib/rom/rails/tasks/db.rake +3 -7
- data/lib/rom/rails/version.rb +1 -1
- data/rom-rails.gemspec +1 -1
- data/spec/dummy/app/mappers/users.rb +1 -0
- data/spec/dummy/app/relations/dummy_relation.rb +1 -1
- data/spec/dummy/config/initializers/rom.rb +2 -2
- data/spec/dummy/db/migrate/20141110205016_add_users.rb +1 -0
- data/spec/dummy/lib/rom/test_adapter.rb +1 -1
- data/spec/{dummy/spec/features → features}/users_spec.rb +0 -0
- data/spec/{dummy/spec/integration → integration}/activerecord_setup.rb +1 -1
- data/spec/{dummy/spec/integration → integration}/form_with_injected_commands_spec.rb +0 -0
- data/spec/integration/initializer_spec.rb +11 -0
- data/spec/{dummy/spec/integration → integration}/logger_spec.rb +3 -3
- data/spec/{dummy/spec/integration → integration}/new_user_form_spec.rb +0 -0
- data/spec/{dummy/spec/integration → integration}/user_attributes_spec.rb +0 -0
- data/spec/{dummy/spec/integration → integration}/user_commands_spec.rb +0 -0
- data/spec/{dummy/spec/integration → integration}/user_model_mapping_spec.rb +0 -0
- data/spec/lib/generators/relation_generator_spec.rb +4 -4
- data/spec/spec_helper.rb +2 -2
- data/spec/unit/validator/embedded_spec.rb +118 -0
- data/spec/unit/validator_spec.rb +68 -3
- metadata +26 -24
- data/spec/dummy/spec/integration/initializer_spec.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3eb6dc7cbe13616ba42eb04dedbf46d454e5fee6
|
4
|
+
data.tar.gz: 3de6f1246346eda7234baec3ada3af5ee425603a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7f4f2a71ecc81887fee3c3fd326119af378d3a633dcadcab03191b7410756bbcf39db3ba65d5e1b78e498469299c0de1511b340cd0af861a99ae76a8b3085b64
|
7
|
+
data.tar.gz: 89106263fa73c8346e2eb7b0062e1c7386c7995e0a9630ae490b40adf5f6e7fde3e6f943b1b1c07d36154469f9f8bf94d0b4004f5dd6e5b8f0e26487a2ab16b6
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,22 @@
|
|
1
|
+
## v0.4.0 2015-06-22
|
2
|
+
|
3
|
+
### Added
|
4
|
+
|
5
|
+
* `embedded` validators allowing to nest validations for embedded values (solnic)
|
6
|
+
* Uniqueness validation supports `:scope` option (vrish88)
|
7
|
+
|
8
|
+
### Changed
|
9
|
+
|
10
|
+
* `ROM.env` is lazy-finalized on first access of any of the components (solnic)
|
11
|
+
* `db:setup` provided by the railtie now loads `:environment` (solnic)
|
12
|
+
* `repositories` in railtie configuration deprecated in favor of `gateways` (solnic)
|
13
|
+
|
14
|
+
### Fixed
|
15
|
+
|
16
|
+
* `method_missing` in validators behaves properly now (solnic)
|
17
|
+
|
18
|
+
[Compare v0.3.3...v0.4.0](https://github.com/rom-rb/rom-rails/compare/v0.3.3...v0.4.0)
|
19
|
+
|
1
20
|
## v0.3.3 2015-05-22
|
2
21
|
|
3
22
|
### Added
|
@@ -1,8 +1,8 @@
|
|
1
1
|
class <%= class_name %>Relation < ROM::Relation<%= "[:#{adapter}]" %>
|
2
|
-
<% if
|
3
|
-
|
2
|
+
<% if gateway -%>
|
3
|
+
gateway :<%= gateway %>
|
4
4
|
<% else -%>
|
5
|
-
#
|
5
|
+
# gateway :default
|
6
6
|
<% end -%>
|
7
7
|
|
8
8
|
dataset :<%= dataset %>
|
@@ -8,9 +8,9 @@ module ROM
|
|
8
8
|
desc: "specify an adapter to use", required: true,
|
9
9
|
default: ROM.adapters.keys.first
|
10
10
|
|
11
|
-
class_option :
|
12
|
-
banner: "--
|
13
|
-
desc: "specify a
|
11
|
+
class_option :gateway,
|
12
|
+
banner: "--gateway=repo",
|
13
|
+
desc: "specify a gateway to connect to",
|
14
14
|
required: false
|
15
15
|
|
16
16
|
class_option :register,
|
@@ -40,8 +40,8 @@ module ROM
|
|
40
40
|
options[:register] || dataset
|
41
41
|
end
|
42
42
|
|
43
|
-
def
|
44
|
-
options[:
|
43
|
+
def gateway
|
44
|
+
options[:gateway]
|
45
45
|
end
|
46
46
|
|
47
47
|
end
|
@@ -17,7 +17,7 @@ module ROM
|
|
17
17
|
:root
|
18
18
|
].freeze
|
19
19
|
|
20
|
-
# Returns
|
20
|
+
# Returns gateway configuration for the current environment.
|
21
21
|
#
|
22
22
|
# @note This relies on ActiveRecord being initialized already.
|
23
23
|
# @param [Rails::Application]
|
@@ -1,11 +1,16 @@
|
|
1
1
|
require 'virtus'
|
2
|
+
require 'rom/support/deprecations'
|
2
3
|
|
3
4
|
module ROM
|
4
5
|
module Rails
|
5
6
|
class Configuration
|
7
|
+
extend ROM::Deprecations
|
8
|
+
|
6
9
|
include Virtus.model(strict: true)
|
7
10
|
|
8
|
-
attribute :
|
11
|
+
attribute :gateways, Hash, default: {}
|
12
|
+
|
13
|
+
deprecate :repositories, :gateways
|
9
14
|
end
|
10
15
|
end
|
11
16
|
end
|
@@ -431,8 +431,8 @@ module ROM
|
|
431
431
|
klass.validator @validator
|
432
432
|
|
433
433
|
relation = rom.relations[rel_name]
|
434
|
-
|
435
|
-
|
434
|
+
gateway = rom.gateways[relation.gateway]
|
435
|
+
gateway.extend_command_class(klass, relation.dataset)
|
436
436
|
|
437
437
|
klass.build(relation)
|
438
438
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'rom/rails/model/validator/uniqueness_validator'
|
2
|
+
require 'rom/support/class_macros'
|
2
3
|
|
3
4
|
module ROM
|
4
5
|
module Model
|
@@ -30,8 +31,14 @@ module ROM
|
|
30
31
|
def self.included(base)
|
31
32
|
base.class_eval do
|
32
33
|
extend ClassMethods
|
34
|
+
extend ROM::ClassMacros
|
35
|
+
|
33
36
|
include ActiveModel::Validations
|
34
37
|
include Equalizer.new(:attributes, :errors)
|
38
|
+
|
39
|
+
base.defines :embedded_validators
|
40
|
+
|
41
|
+
embedded_validators({})
|
35
42
|
end
|
36
43
|
end
|
37
44
|
|
@@ -40,11 +47,15 @@ module ROM
|
|
40
47
|
# @api private
|
41
48
|
attr_reader :attributes
|
42
49
|
|
50
|
+
# @api private
|
51
|
+
attr_reader :attr_names
|
52
|
+
|
43
53
|
delegate :model_name, to: :attributes
|
44
54
|
|
45
55
|
# @api private
|
46
56
|
def initialize(attributes)
|
47
57
|
@attributes = attributes
|
58
|
+
@attr_names = self.class.validators.map(&:attributes).flatten.uniq
|
48
59
|
end
|
49
60
|
|
50
61
|
# @return [Model::Attributes]
|
@@ -72,8 +83,12 @@ module ROM
|
|
72
83
|
# as it expects the object to provide attribute values. Meh.
|
73
84
|
#
|
74
85
|
# @api private
|
75
|
-
def method_missing(name)
|
76
|
-
|
86
|
+
def method_missing(name, *args, &block)
|
87
|
+
if attr_names.include?(name)
|
88
|
+
attributes[name]
|
89
|
+
else
|
90
|
+
super
|
91
|
+
end
|
77
92
|
end
|
78
93
|
|
79
94
|
module ClassMethods
|
@@ -99,9 +114,13 @@ module ROM
|
|
99
114
|
@relation
|
100
115
|
end
|
101
116
|
|
102
|
-
#
|
103
|
-
def
|
104
|
-
|
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
|
105
124
|
end
|
106
125
|
|
107
126
|
# Trigger validation for specific attributes
|
@@ -115,6 +134,57 @@ module ROM
|
|
115
134
|
validator = new(attributes)
|
116
135
|
validator.call
|
117
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
|
118
188
|
end
|
119
189
|
end
|
120
190
|
end
|
@@ -24,13 +24,17 @@ module ROM
|
|
24
24
|
super
|
25
25
|
@klass = options.fetch(:class)
|
26
26
|
@message = options.fetch(:message) { :taken }
|
27
|
+
@scope_keys = options[:scope]
|
27
28
|
end
|
28
29
|
|
29
30
|
# Hook called by ActiveModel internally
|
30
31
|
#
|
31
32
|
# @api private
|
32
33
|
def validate_each(validator, name, value)
|
33
|
-
|
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)
|
34
38
|
end
|
35
39
|
|
36
40
|
private
|
@@ -66,8 +70,8 @@ module ROM
|
|
66
70
|
# @return [TrueClass,FalseClass]
|
67
71
|
#
|
68
72
|
# @api private
|
69
|
-
def unique?(name, value)
|
70
|
-
relation.unique?(name => value)
|
73
|
+
def unique?(name, value, scope)
|
74
|
+
relation.unique?({name => value}.merge(scope))
|
71
75
|
end
|
72
76
|
end
|
73
77
|
end
|
data/lib/rom/rails/railtie.rb
CHANGED
@@ -12,42 +12,11 @@ module ROM
|
|
12
12
|
class Railtie < ::Rails::Railtie
|
13
13
|
COMPONENT_DIRS = %w(relations mappers commands).freeze
|
14
14
|
|
15
|
-
|
15
|
+
MissingGatewayConfigError = Class.new(StandardError)
|
16
16
|
|
17
|
-
#
|
18
|
-
|
19
|
-
|
20
|
-
MissingRepositoryConfigError,
|
21
|
-
"seems like you didn't configure any repositories"
|
22
|
-
) unless config.rom.repositories.any?
|
23
|
-
|
24
|
-
ROM.setup(config.rom.repositories)
|
25
|
-
self
|
26
|
-
end
|
27
|
-
|
28
|
-
# @api public
|
29
|
-
def self.finalize
|
30
|
-
ROM.finalize
|
31
|
-
self
|
32
|
-
end
|
33
|
-
|
34
|
-
# If there's no default repository configured, try to infer it from
|
35
|
-
# other sources, e.g. ActiveRecord.
|
36
|
-
#
|
37
|
-
# @api private
|
38
|
-
def self.infer_default_repository
|
39
|
-
return unless active_record?
|
40
|
-
spec = ROM::Rails::ActiveRecord::Configuration.call
|
41
|
-
[:sql, spec[:uri], spec[:options]]
|
42
|
-
end
|
43
|
-
|
44
|
-
# @api private
|
45
|
-
def self.active_record?
|
46
|
-
defined?(::ActiveRecord)
|
47
|
-
end
|
48
|
-
|
49
|
-
# @api private
|
50
|
-
def before_initialize
|
17
|
+
# Make `ROM::Rails::Configuration` instance available to the user via
|
18
|
+
# `Rails.application.config` before other initializers run.
|
19
|
+
config.before_initialize do |_app|
|
51
20
|
config.rom = Configuration.new
|
52
21
|
end
|
53
22
|
|
@@ -59,25 +28,19 @@ module ROM
|
|
59
28
|
|
60
29
|
initializer 'rom.adjust_eager_load_paths' do |app|
|
61
30
|
paths = COMPONENT_DIRS.map do |directory|
|
62
|
-
|
31
|
+
root.join('app', directory).to_s
|
63
32
|
end
|
64
33
|
|
65
|
-
app.config.eager_load_paths -=
|
34
|
+
app.config.eager_load_paths -= paths
|
66
35
|
end
|
67
36
|
|
68
37
|
rake_tasks do
|
69
|
-
load "rom/rails/tasks/db.rake" unless
|
70
|
-
end
|
71
|
-
|
72
|
-
# Make `ROM::Rails::Configuration` instance available to the user via
|
73
|
-
# `Rails.application.config` before other initializers run.
|
74
|
-
config.before_initialize do |_app|
|
75
|
-
before_initialize
|
38
|
+
load "rom/rails/tasks/db.rake" unless active_record?
|
76
39
|
end
|
77
40
|
|
78
41
|
# Reload ROM-related application code on each request.
|
79
42
|
config.to_prepare do |_config|
|
80
|
-
Railtie.
|
43
|
+
Railtie.finalize
|
81
44
|
end
|
82
45
|
|
83
46
|
# Behaves like `Railtie#configure` if the given block does not take any
|
@@ -85,11 +48,13 @@ module ROM
|
|
85
48
|
#
|
86
49
|
# @example
|
87
50
|
# ROM::Rails::Railtie.configure do |config|
|
88
|
-
# config.
|
51
|
+
# config.gateways[:default] = [:yaml, 'yaml:///data']
|
89
52
|
# end
|
90
53
|
#
|
91
54
|
# @api public
|
92
55
|
def configure(&block)
|
56
|
+
config.rom = Configuration.new unless config.respond_to?(:rom)
|
57
|
+
|
93
58
|
if block.arity == 1
|
94
59
|
block.call(config.rom)
|
95
60
|
else
|
@@ -97,40 +62,69 @@ module ROM
|
|
97
62
|
end
|
98
63
|
end
|
99
64
|
|
65
|
+
# @api private
|
66
|
+
def setup(gateways)
|
67
|
+
raise(
|
68
|
+
MissingGatewayConfigError,
|
69
|
+
"seems like you didn't configure any gateways"
|
70
|
+
) unless gateways.any?
|
71
|
+
|
72
|
+
ROM.setup(gateways)
|
73
|
+
end
|
74
|
+
|
75
|
+
# @api private
|
76
|
+
def setup_gateways
|
77
|
+
gateways =
|
78
|
+
if env
|
79
|
+
env.gateways
|
80
|
+
else
|
81
|
+
prepare_gateways
|
82
|
+
end
|
83
|
+
|
84
|
+
setup(gateways)
|
85
|
+
end
|
86
|
+
|
87
|
+
# @api private
|
88
|
+
def finalize
|
89
|
+
setup_gateways
|
90
|
+
load_components
|
91
|
+
ROM.finalize
|
92
|
+
end
|
93
|
+
|
100
94
|
# TODO: Add `ROM.env.disconnect` to core.
|
101
95
|
#
|
102
96
|
# @api private
|
103
97
|
def disconnect
|
104
|
-
ROM.
|
98
|
+
ROM.gateways.each_key(&:disconnect)
|
105
99
|
end
|
106
100
|
|
107
101
|
# @api private
|
108
|
-
def
|
109
|
-
if
|
110
|
-
|
111
|
-
|
112
|
-
repositories = config.rom.repositories
|
102
|
+
def prepare_gateways
|
103
|
+
config.rom.gateways[:default] ||= infer_default_gateway if active_record?
|
104
|
+
config.rom.gateways
|
105
|
+
end
|
113
106
|
|
114
|
-
|
115
|
-
|
116
|
-
|
107
|
+
# If there's no default gateway configured, try to infer it from
|
108
|
+
# other sources, e.g. ActiveRecord.
|
109
|
+
#
|
110
|
+
# @api private
|
111
|
+
def infer_default_gateway
|
112
|
+
spec = ROM::Rails::ActiveRecord::Configuration.call
|
113
|
+
[:sql, spec[:uri], spec[:options]]
|
114
|
+
end
|
117
115
|
|
118
|
-
|
119
|
-
|
120
|
-
load_all
|
121
|
-
self.class.finalize
|
116
|
+
def load_initializer
|
117
|
+
load "#{root}/config/initializers/rom.rb" rescue LoadError
|
122
118
|
end
|
123
119
|
|
124
120
|
# @api private
|
125
|
-
def
|
126
|
-
COMPONENT_DIRS.each
|
127
|
-
load_files(type)
|
128
|
-
end
|
121
|
+
def load_components
|
122
|
+
COMPONENT_DIRS.each { |type| load_files(type) }
|
129
123
|
end
|
130
124
|
|
131
125
|
# @api private
|
132
126
|
def load_files(type)
|
133
|
-
Dir[root.join("app/#{type}/**/*.rb")
|
127
|
+
Dir[root.join("app/#{type}/**/*.rb")].each do |path|
|
134
128
|
require_dependency(path)
|
135
129
|
end
|
136
130
|
end
|
@@ -139,6 +133,16 @@ module ROM
|
|
139
133
|
def root
|
140
134
|
::Rails.root
|
141
135
|
end
|
136
|
+
|
137
|
+
# @api private
|
138
|
+
def env
|
139
|
+
ROM.env
|
140
|
+
end
|
141
|
+
|
142
|
+
# @api private
|
143
|
+
def active_record?
|
144
|
+
defined?(::ActiveRecord)
|
145
|
+
end
|
142
146
|
end
|
143
147
|
end
|
144
148
|
end
|
data/lib/rom/rails/tasks/db.rake
CHANGED
@@ -1,11 +1,7 @@
|
|
1
1
|
namespace :db do
|
2
|
-
desc 'Set up ROM
|
2
|
+
desc 'Set up ROM gateways'
|
3
3
|
task :setup do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
require "#{Rails.root}/config/initializers/rom"
|
8
|
-
|
9
|
-
railtie.setup_repositories.finalize
|
4
|
+
ROM::Rails::Railtie.load_initializer
|
5
|
+
ROM::Rails::Railtie.setup_gateways
|
10
6
|
end
|
11
7
|
end
|
data/lib/rom/rails/version.rb
CHANGED
data/rom-rails.gemspec
CHANGED
@@ -17,7 +17,7 @@ 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.
|
20
|
+
spec.add_runtime_dependency 'rom', '~> 0.8', '>= 0.8.0'
|
21
21
|
spec.add_runtime_dependency 'addressable', '~> 2.3'
|
22
22
|
spec.add_runtime_dependency 'charlatan', '~> 0.1'
|
23
23
|
spec.add_runtime_dependency 'virtus', '~> 1.0', '>= 1.0.5'
|
@@ -1,5 +1,5 @@
|
|
1
1
|
ROM::Rails::Railtie.configure do |config|
|
2
2
|
scheme = RUBY_ENGINE == 'jruby' ? 'jdbc:sqlite' : 'sqlite'
|
3
|
-
config.
|
4
|
-
config.
|
3
|
+
config.gateways[:default] = [:sql, "#{scheme}://#{Rails.root}/db/#{Rails.env}.sqlite3"]
|
4
|
+
config.gateways[:test] = [:test_adapter, foo: :bar]
|
5
5
|
end
|
File without changes
|
File without changes
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'ROM initializer' do
|
4
|
+
it 'allows setting up a custom gateway' do
|
5
|
+
gateway = ROM::TestAdapter::Gateway.new(foo: :bar)
|
6
|
+
relation = DummyRelation.new([])
|
7
|
+
|
8
|
+
expect(rom.gateways[:test]).to eql(gateway)
|
9
|
+
expect(rom.relations.dummy).to eql(relation)
|
10
|
+
end
|
11
|
+
end
|
@@ -3,12 +3,12 @@ require 'spec_helper'
|
|
3
3
|
describe 'ROM logger' do
|
4
4
|
let(:rom) { ROM.env }
|
5
5
|
|
6
|
-
it 'sets up rails logger for all
|
6
|
+
it 'sets up rails logger for all gateways' do
|
7
7
|
pending 'this will be re-enabled once we have feature detection on ' \
|
8
8
|
'adapters and in case of missing rails-log-subscriber support we ' \
|
9
9
|
'will set logger to Rails.logger'
|
10
|
-
rom.
|
11
|
-
expect(
|
10
|
+
rom.gateways.each_value do |gateway|
|
11
|
+
expect(gateway.logger).to be(Rails.logger)
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -19,7 +19,7 @@ describe ROM::Generators::RelationGenerator, type: :generator do
|
|
19
19
|
file 'users_relation.rb' do
|
20
20
|
contains <<-CONTENT.strip_heredoc
|
21
21
|
class UsersRelation < ROM::Relation[:#{default_adapter}]
|
22
|
-
#
|
22
|
+
# gateway :default
|
23
23
|
|
24
24
|
dataset :users
|
25
25
|
|
@@ -45,11 +45,11 @@ describe ROM::Generators::RelationGenerator, type: :generator do
|
|
45
45
|
expect(relation).to include("class UsersRelation < ROM::Relation[:memory]")
|
46
46
|
end
|
47
47
|
|
48
|
-
specify "with given
|
49
|
-
run_generator ['users', '--
|
48
|
+
specify "with given gateway" do
|
49
|
+
run_generator ['users', '--gateway=remote']
|
50
50
|
|
51
51
|
relation = File.read(File.join(destination_root, 'app', 'relations', 'users_relation.rb'))
|
52
|
-
expect(relation).to include("
|
52
|
+
expect(relation).to include("gateway :remote")
|
53
53
|
end
|
54
54
|
|
55
55
|
specify "with given registration" do
|
data/spec/spec_helper.rb
CHANGED
@@ -24,14 +24,14 @@ RSpec.configure do |config|
|
|
24
24
|
config.order = "random"
|
25
25
|
|
26
26
|
config.before(:suite) do
|
27
|
-
conn = ROM.env.
|
27
|
+
conn = ROM.env.gateways[:default].connection
|
28
28
|
|
29
29
|
DatabaseCleaner[:sequel, connection: conn].strategy = :transaction
|
30
30
|
DatabaseCleaner[:sequel, connection: conn].clean_with(:truncation)
|
31
31
|
end
|
32
32
|
|
33
33
|
config.around(:each) do |example|
|
34
|
-
conn = ROM.env.
|
34
|
+
conn = ROM.env.gateways[:default].connection
|
35
35
|
|
36
36
|
DatabaseCleaner[:sequel, connection: conn].cleaning { example.run }
|
37
37
|
end
|
@@ -0,0 +1,118 @@
|
|
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
CHANGED
@@ -11,6 +11,7 @@ describe 'Validation' do
|
|
11
11
|
|
12
12
|
attribute :name, String
|
13
13
|
attribute :email, String
|
14
|
+
attribute :birthday, Date
|
14
15
|
}
|
15
16
|
end
|
16
17
|
|
@@ -58,11 +59,9 @@ describe 'Validation' do
|
|
58
59
|
describe ':uniqueness' do
|
59
60
|
let(:attributes) { user_attrs.new(name: 'Jane', email: 'jane@doe.org') }
|
60
61
|
|
61
|
-
|
62
|
+
it 'sets default error messages' do
|
62
63
|
rom.relations.users.insert(name: 'Jane', email: 'jane@doe.org')
|
63
|
-
end
|
64
64
|
|
65
|
-
it 'sets default error messages' do
|
66
65
|
expect(validator).to_not be_valid
|
67
66
|
expect(validator.errors[:email]).to eql(['has already been taken'])
|
68
67
|
end
|
@@ -73,5 +72,71 @@ describe 'Validation' do
|
|
73
72
|
expect(validator).to_not be_valid
|
74
73
|
expect(validator.errors[:name]).to eql(['TAKEN!'])
|
75
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
|
+
end
|
126
|
+
|
127
|
+
describe '#method_missing' do
|
128
|
+
let(:attributes) { { name: 'Jane' } }
|
129
|
+
|
130
|
+
it 'returns attribute value if present' do
|
131
|
+
expect(validator.name).to eql('Jane')
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'returns nil if attribute is not present' do
|
135
|
+
expect(validator.email).to be(nil)
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'raises error when name does not match any of the attributes' do
|
139
|
+
expect { validator.foobar }.to raise_error(NoMethodError, /foobar/)
|
140
|
+
end
|
76
141
|
end
|
77
142
|
end
|
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.
|
4
|
+
version: 0.4.0
|
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-
|
11
|
+
date: 2015-06-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rom
|
@@ -16,20 +16,20 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0.
|
19
|
+
version: '0.8'
|
20
20
|
- - ">="
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: 0.
|
22
|
+
version: 0.8.0
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
27
|
- - "~>"
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: '0.
|
29
|
+
version: '0.8'
|
30
30
|
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: 0.
|
32
|
+
version: 0.8.0
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: addressable
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -241,17 +241,17 @@ files:
|
|
241
241
|
- spec/dummy/public/500.html
|
242
242
|
- spec/dummy/public/favicon.ico
|
243
243
|
- spec/dummy/public/robots.txt
|
244
|
-
- spec/dummy/spec/features/users_spec.rb
|
245
|
-
- spec/dummy/spec/integration/activerecord_setup.rb
|
246
|
-
- spec/dummy/spec/integration/form_with_injected_commands_spec.rb
|
247
|
-
- spec/dummy/spec/integration/initializer_spec.rb
|
248
|
-
- spec/dummy/spec/integration/logger_spec.rb
|
249
|
-
- spec/dummy/spec/integration/new_user_form_spec.rb
|
250
|
-
- spec/dummy/spec/integration/user_attributes_spec.rb
|
251
|
-
- spec/dummy/spec/integration/user_commands_spec.rb
|
252
|
-
- spec/dummy/spec/integration/user_model_mapping_spec.rb
|
253
244
|
- spec/dummy/vendor/assets/javascripts/.keep
|
254
245
|
- spec/dummy/vendor/assets/stylesheets/.keep
|
246
|
+
- spec/features/users_spec.rb
|
247
|
+
- spec/integration/activerecord_setup.rb
|
248
|
+
- spec/integration/form_with_injected_commands_spec.rb
|
249
|
+
- spec/integration/initializer_spec.rb
|
250
|
+
- spec/integration/logger_spec.rb
|
251
|
+
- spec/integration/new_user_form_spec.rb
|
252
|
+
- spec/integration/user_attributes_spec.rb
|
253
|
+
- spec/integration/user_commands_spec.rb
|
254
|
+
- spec/integration/user_model_mapping_spec.rb
|
255
255
|
- spec/lib/active_record/configuration_spec.rb
|
256
256
|
- spec/lib/generators/commands_generator_spec.rb
|
257
257
|
- spec/lib/generators/form_generator_spec.rb
|
@@ -259,6 +259,7 @@ files:
|
|
259
259
|
- spec/lib/generators/relation_generator_spec.rb
|
260
260
|
- spec/spec_helper.rb
|
261
261
|
- spec/unit/form_spec.rb
|
262
|
+
- spec/unit/validator/embedded_spec.rb
|
262
263
|
- spec/unit/validator_spec.rb
|
263
264
|
homepage: http://rom-rb.org
|
264
265
|
licenses:
|
@@ -341,17 +342,17 @@ test_files:
|
|
341
342
|
- spec/dummy/public/500.html
|
342
343
|
- spec/dummy/public/favicon.ico
|
343
344
|
- spec/dummy/public/robots.txt
|
344
|
-
- spec/dummy/spec/features/users_spec.rb
|
345
|
-
- spec/dummy/spec/integration/activerecord_setup.rb
|
346
|
-
- spec/dummy/spec/integration/form_with_injected_commands_spec.rb
|
347
|
-
- spec/dummy/spec/integration/initializer_spec.rb
|
348
|
-
- spec/dummy/spec/integration/logger_spec.rb
|
349
|
-
- spec/dummy/spec/integration/new_user_form_spec.rb
|
350
|
-
- spec/dummy/spec/integration/user_attributes_spec.rb
|
351
|
-
- spec/dummy/spec/integration/user_commands_spec.rb
|
352
|
-
- spec/dummy/spec/integration/user_model_mapping_spec.rb
|
353
345
|
- spec/dummy/vendor/assets/javascripts/.keep
|
354
346
|
- spec/dummy/vendor/assets/stylesheets/.keep
|
347
|
+
- spec/features/users_spec.rb
|
348
|
+
- spec/integration/activerecord_setup.rb
|
349
|
+
- spec/integration/form_with_injected_commands_spec.rb
|
350
|
+
- spec/integration/initializer_spec.rb
|
351
|
+
- spec/integration/logger_spec.rb
|
352
|
+
- spec/integration/new_user_form_spec.rb
|
353
|
+
- spec/integration/user_attributes_spec.rb
|
354
|
+
- spec/integration/user_commands_spec.rb
|
355
|
+
- spec/integration/user_model_mapping_spec.rb
|
355
356
|
- spec/lib/active_record/configuration_spec.rb
|
356
357
|
- spec/lib/generators/commands_generator_spec.rb
|
357
358
|
- spec/lib/generators/form_generator_spec.rb
|
@@ -359,4 +360,5 @@ test_files:
|
|
359
360
|
- spec/lib/generators/relation_generator_spec.rb
|
360
361
|
- spec/spec_helper.rb
|
361
362
|
- spec/unit/form_spec.rb
|
363
|
+
- spec/unit/validator/embedded_spec.rb
|
362
364
|
- spec/unit/validator_spec.rb
|
@@ -1,11 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe 'ROM initializer' do
|
4
|
-
it 'allows setting up a custom repository' do
|
5
|
-
repository = ROM::TestAdapter::Repository.new(foo: :bar)
|
6
|
-
relation = DummyRelation.new([])
|
7
|
-
|
8
|
-
expect(rom.repositories[:test]).to eql(repository)
|
9
|
-
expect(rom.relations.dummy).to eql(relation)
|
10
|
-
end
|
11
|
-
end
|