rom-rails 0.3.3 → 0.4.0
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/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
|