rom-rails 0.3.0.beta1 → 0.3.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/CHANGELOG.md +1 -1
- data/lib/generators/rom/form/templates/edit_form.rb.erb +1 -1
- data/lib/generators/rom/form/templates/new_form.rb.erb +1 -1
- data/lib/generators/rom/mapper/templates/mapper.rb.erb +2 -2
- data/lib/rom/model.rb +1 -1
- data/lib/rom/rails/controller_extension.rb +0 -35
- data/lib/rom/rails/model/attributes.rb +133 -0
- data/lib/rom/rails/model/form.rb +96 -5
- data/lib/rom/rails/model/form/class_interface.rb +401 -0
- data/lib/rom/rails/model/validator.rb +62 -15
- data/lib/rom/rails/model/validator/uniqueness_validator.rb +37 -1
- data/lib/rom/rails/version.rb +1 -1
- data/rom-rails.gemspec +2 -2
- data/spec/dummy/app/controllers/users_controller.rb +7 -8
- data/spec/dummy/app/forms/new_user_form.rb +2 -2
- data/spec/dummy/app/forms/update_user_form.rb +2 -2
- data/spec/dummy/spec/integration/{user_params_spec.rb → user_attributes_spec.rb} +11 -11
- data/spec/dummy/spec/integration/user_model_mapping_spec.rb +1 -1
- data/spec/lib/generators/form_generator_spec.rb +2 -2
- data/spec/lib/generators/mapper_generator_spec.rb +2 -2
- data/spec/unit/form_spec.rb +20 -16
- data/spec/unit/validator_spec.rb +9 -9
- metadata +11 -16
- data/lib/rom/rails/model/form/dsl.rb +0 -173
- data/lib/rom/rails/model/params.rb +0 -72
- data/spec/dummy/spec/controllers/users_controller_spec.rb +0 -29
- data/spec/unit/params_spec.rb +0 -23
@@ -7,8 +7,8 @@ module ROM
|
|
7
7
|
# @example
|
8
8
|
#
|
9
9
|
#
|
10
|
-
# class
|
11
|
-
# include ROM::Model::
|
10
|
+
# class UserAttributes
|
11
|
+
# include ROM::Model::Attributes
|
12
12
|
#
|
13
13
|
# attribute :name
|
14
14
|
#
|
@@ -19,53 +19,100 @@ module ROM
|
|
19
19
|
# include ROM::Model::Validator
|
20
20
|
# end
|
21
21
|
#
|
22
|
-
#
|
23
|
-
# UserValidator.call(
|
22
|
+
# attrs = UserAttributes.new(name: '')
|
23
|
+
# UserValidator.call(attrs) # raises ValidationError
|
24
24
|
#
|
25
25
|
# @api public
|
26
26
|
module Validator
|
27
|
+
# Inclusion hook that extends a class with required interfaces
|
28
|
+
#
|
29
|
+
# @api private
|
27
30
|
def self.included(base)
|
28
31
|
base.class_eval do
|
29
32
|
extend ClassMethods
|
30
33
|
include ActiveModel::Validations
|
31
|
-
include Equalizer.new(:
|
34
|
+
include Equalizer.new(:attributes, :errors)
|
32
35
|
end
|
33
36
|
end
|
34
37
|
|
35
|
-
|
36
|
-
|
38
|
+
# @return [Model::Attributes]
|
39
|
+
#
|
40
|
+
# @api private
|
41
|
+
attr_reader :attributes
|
37
42
|
|
38
|
-
|
39
|
-
|
43
|
+
delegate :model_name, to: :attributes
|
44
|
+
|
45
|
+
# @api private
|
46
|
+
def initialize(attributes)
|
47
|
+
@attributes = attributes
|
40
48
|
end
|
41
49
|
|
50
|
+
# @return [Model::Attributes]
|
51
|
+
#
|
52
|
+
# @api public
|
42
53
|
def to_model
|
43
|
-
|
54
|
+
attributes
|
44
55
|
end
|
45
56
|
|
57
|
+
# Trigger validations and return attributes on success
|
58
|
+
#
|
59
|
+
# @raises ValidationError
|
60
|
+
#
|
61
|
+
# @return [Model::Attributes]
|
62
|
+
#
|
63
|
+
# @api public
|
46
64
|
def call
|
47
65
|
raise ValidationError, errors unless valid?
|
48
|
-
|
66
|
+
attributes
|
49
67
|
end
|
50
68
|
|
51
69
|
private
|
52
70
|
|
71
|
+
# This is needed for ActiveModel::Validations to work properly
|
72
|
+
# as it expects the object to provide attribute values. Meh.
|
73
|
+
#
|
74
|
+
# @api private
|
53
75
|
def method_missing(name)
|
54
|
-
|
76
|
+
attributes[name]
|
55
77
|
end
|
56
78
|
|
57
79
|
module ClassMethods
|
80
|
+
# Set relation name for a validator
|
81
|
+
#
|
82
|
+
# This is needed for validators that require database access
|
83
|
+
#
|
84
|
+
# @example
|
85
|
+
#
|
86
|
+
# class UserValidator
|
87
|
+
# include ROM::Model::Validator
|
88
|
+
#
|
89
|
+
# relation :users
|
90
|
+
#
|
91
|
+
# validates :name, uniqueness: true
|
92
|
+
# end
|
93
|
+
#
|
94
|
+
# @return [Symbol]
|
95
|
+
#
|
96
|
+
# @api public
|
58
97
|
def relation(name = nil)
|
59
98
|
@relation = name if name
|
60
99
|
@relation
|
61
100
|
end
|
62
101
|
|
102
|
+
# FIXME: this looks like not needed
|
63
103
|
def model_name
|
64
|
-
|
104
|
+
attributes.model_name
|
65
105
|
end
|
66
106
|
|
67
|
-
|
68
|
-
|
107
|
+
# Trigger validation for specific attributes
|
108
|
+
#
|
109
|
+
# @param [Model::Attributes] attributes The attributes for validation
|
110
|
+
#
|
111
|
+
# @raises [ValidationError]
|
112
|
+
#
|
113
|
+
# @return [Model::Attributes]
|
114
|
+
def call(attributes)
|
115
|
+
validator = new(attributes)
|
69
116
|
validator.call
|
70
117
|
end
|
71
118
|
end
|
@@ -3,33 +3,69 @@ require 'active_model/validator'
|
|
3
3
|
module ROM
|
4
4
|
module Model
|
5
5
|
module Validator
|
6
|
+
# Uniqueness validation
|
7
|
+
#
|
8
|
+
# @api public
|
6
9
|
class UniquenessValidator < ActiveModel::EachValidator
|
7
|
-
|
10
|
+
# Relation validator class
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
attr_reader :klass
|
8
14
|
|
15
|
+
# error message
|
16
|
+
#
|
17
|
+
# @return [String, Symbol]
|
18
|
+
#
|
19
|
+
# @api private
|
20
|
+
attr_reader :message
|
21
|
+
|
22
|
+
# @api private
|
9
23
|
def initialize(options)
|
10
24
|
super
|
11
25
|
@klass = options.fetch(:class)
|
12
26
|
@message = options.fetch(:message) { :taken }
|
13
27
|
end
|
14
28
|
|
29
|
+
# Hook called by ActiveModel internally
|
30
|
+
#
|
31
|
+
# @api private
|
15
32
|
def validate_each(validator, name, value)
|
16
33
|
validator.errors.add(name, message) unless unique?(name, value)
|
17
34
|
end
|
18
35
|
|
19
36
|
private
|
20
37
|
|
38
|
+
# Get relation object from the rom env
|
39
|
+
#
|
40
|
+
# @api private
|
21
41
|
def relation
|
22
42
|
rom.relations[relation_name]
|
23
43
|
end
|
24
44
|
|
45
|
+
# Relation name defined on the validator class
|
46
|
+
#
|
47
|
+
# @api private
|
25
48
|
def relation_name
|
26
49
|
klass.relation
|
27
50
|
end
|
28
51
|
|
52
|
+
# Shortcut to access global rom env
|
53
|
+
#
|
54
|
+
# @return [ROM::Env]
|
55
|
+
#
|
56
|
+
# @api private
|
29
57
|
def rom
|
30
58
|
ROM.env
|
31
59
|
end
|
32
60
|
|
61
|
+
# Ask relation if a given attribute value is unique
|
62
|
+
#
|
63
|
+
# This uses `Relation#unique?` interface that not all adapters can
|
64
|
+
# implement.
|
65
|
+
#
|
66
|
+
# @return [TrueClass,FalseClass]
|
67
|
+
#
|
68
|
+
# @api private
|
33
69
|
def unique?(name, value)
|
34
70
|
relation.unique?(name => value)
|
35
71
|
end
|
data/lib/rom/rails/version.rb
CHANGED
data/rom-rails.gemspec
CHANGED
@@ -17,10 +17,10 @@ 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.6.0.
|
20
|
+
spec.add_runtime_dependency 'rom', '~> 0.6.0.rc1'
|
21
21
|
spec.add_runtime_dependency 'addressable', '~> 2.3'
|
22
22
|
spec.add_runtime_dependency 'charlatan', '~> 0.1'
|
23
|
-
spec.add_runtime_dependency 'virtus', '~> 1.0', '>= 1.0.
|
23
|
+
spec.add_runtime_dependency 'virtus', '~> 1.0', '>= 1.0.5'
|
24
24
|
spec.add_runtime_dependency 'railties', ['>= 3.0', '< 5.0']
|
25
25
|
|
26
26
|
spec.add_development_dependency "bundler"
|
@@ -3,11 +3,14 @@ class UsersController < ApplicationController
|
|
3
3
|
head :bad_request
|
4
4
|
end
|
5
5
|
|
6
|
-
relation 'users.index', only: :index
|
7
|
-
relation 'users.by_name', only: :search, requires: :name
|
8
|
-
|
9
6
|
def index
|
10
|
-
render
|
7
|
+
render :index, locals: { users: rom.relation(:users).as(:users) }
|
8
|
+
end
|
9
|
+
|
10
|
+
def search
|
11
|
+
render :index, locals: {
|
12
|
+
users: rom.relation(:users).as(:users).by_name(params[:name])
|
13
|
+
}
|
11
14
|
end
|
12
15
|
|
13
16
|
def new
|
@@ -40,10 +43,6 @@ class UsersController < ApplicationController
|
|
40
43
|
end
|
41
44
|
end
|
42
45
|
|
43
|
-
def search
|
44
|
-
render :index
|
45
|
-
end
|
46
|
-
|
47
46
|
def ping
|
48
47
|
head :ok
|
49
48
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
class UpdateUserForm < UserForm
|
2
2
|
commands users: :update
|
3
3
|
|
4
|
-
|
4
|
+
attributes.timestamps(:updated_at)
|
5
5
|
|
6
6
|
def commit!
|
7
|
-
users.try { users.update.by_id(id).set(
|
7
|
+
users.try { users.update.by_id(id).set(attributes) }
|
8
8
|
end
|
9
9
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe ROM::Model::
|
4
|
-
let(:
|
3
|
+
describe ROM::Model::Attributes do
|
4
|
+
let(:attributes) do
|
5
5
|
Class.new do
|
6
|
-
include ROM::Model::
|
6
|
+
include ROM::Model::Attributes
|
7
7
|
|
8
8
|
attribute :name, String
|
9
9
|
|
@@ -13,32 +13,32 @@ describe ROM::Model::Params do
|
|
13
13
|
|
14
14
|
describe '.timestamps' do
|
15
15
|
it 'provides a way to specify timestamps with default values' do
|
16
|
-
expect(
|
17
|
-
expect(
|
16
|
+
expect(attributes.new.created_at).to be_a(DateTime)
|
17
|
+
expect(attributes.new.updated_at).to be_a(DateTime)
|
18
18
|
end
|
19
19
|
|
20
20
|
context 'passing in arbritrary names' do
|
21
21
|
it 'excludes :created_at when passing in :updated_at' do
|
22
|
-
|
23
|
-
include ROM::Model::
|
22
|
+
attributes = Class.new {
|
23
|
+
include ROM::Model::Attributes
|
24
24
|
|
25
25
|
timestamps(:updated_at)
|
26
26
|
}
|
27
27
|
|
28
|
-
model =
|
28
|
+
model = attributes.new
|
29
29
|
|
30
30
|
expect(model).not_to respond_to(:created_at)
|
31
31
|
expect(model).to respond_to(:updated_at)
|
32
32
|
end
|
33
33
|
|
34
34
|
it 'accepts multiple timestamp attribute names' do
|
35
|
-
|
36
|
-
include ROM::Model::
|
35
|
+
attributes = Class.new {
|
36
|
+
include ROM::Model::Attributes
|
37
37
|
|
38
38
|
timestamps(:published_at, :revised_at)
|
39
39
|
}
|
40
40
|
|
41
|
-
model =
|
41
|
+
model = attributes.new
|
42
42
|
|
43
43
|
expect(model).to respond_to(:published_at)
|
44
44
|
expect(model).to respond_to(:revised_at)
|
@@ -37,7 +37,7 @@ describe ROM::Generators::FormGenerator do
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def commit!
|
40
|
-
users.try { users.create.call(
|
40
|
+
users.try { users.create.call(attributes) }
|
41
41
|
end
|
42
42
|
|
43
43
|
end
|
@@ -76,7 +76,7 @@ describe ROM::Generators::FormGenerator do
|
|
76
76
|
end
|
77
77
|
|
78
78
|
def commit!
|
79
|
-
users.try { users.update.by_id(id).set(
|
79
|
+
users.try { users.update.by_id(id).set(attributes) }
|
80
80
|
end
|
81
81
|
|
82
82
|
end
|
data/spec/unit/form_spec.rb
CHANGED
@@ -25,17 +25,21 @@ describe 'Form' do
|
|
25
25
|
|
26
26
|
describe '.build' do
|
27
27
|
it 'rejects blank strings from params' do
|
28
|
-
input = {
|
29
|
-
'name' => 'Jane',
|
30
|
-
'hash' => { 'one' => '', 'two' => 2 },
|
31
|
-
'array' => [{ 'three' => '', 'four' => 4 }, 5]
|
32
|
-
}
|
28
|
+
input = { 'name' => '' }
|
33
29
|
|
34
30
|
form_object = form.build(input)
|
35
31
|
|
36
|
-
expect(form_object.
|
37
|
-
|
38
|
-
|
32
|
+
expect(form_object.attributes.to_h).to eql(email: nil)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'exposes param values' do
|
36
|
+
params = { 'email' => 'jane@doe.org' }
|
37
|
+
form_object = form.build(params)
|
38
|
+
expect(form_object.email).to eql('jane@doe.org')
|
39
|
+
|
40
|
+
params = { email: 'jane@doe.org' }
|
41
|
+
form_object = form.build(params)
|
42
|
+
expect(form_object.email).to eql('jane@doe.org')
|
39
43
|
end
|
40
44
|
end
|
41
45
|
|
@@ -48,7 +52,7 @@ describe 'Form' do
|
|
48
52
|
validations { validates :name, presence: true }
|
49
53
|
|
50
54
|
def commit!
|
51
|
-
users.try { users.create.call(
|
55
|
+
users.try { users.create.call(attributes) }
|
52
56
|
end
|
53
57
|
}
|
54
58
|
|
@@ -94,16 +98,16 @@ describe 'Form' do
|
|
94
98
|
end
|
95
99
|
|
96
100
|
describe '.model_name' do
|
97
|
-
it 'delegates to
|
98
|
-
expect(form.model_name).to be(form.
|
101
|
+
it 'delegates to Attributes.model_name' do
|
102
|
+
expect(form.model_name).to be(form.attributes.model_name)
|
99
103
|
end
|
100
104
|
end
|
101
105
|
|
102
106
|
describe 'input DSL' do
|
103
107
|
it 'defines params handler' do
|
104
|
-
expect(form.const_defined?(:
|
105
|
-
expect(form.
|
106
|
-
expect(form.
|
108
|
+
expect(form.const_defined?(:Attributes)).to be(true)
|
109
|
+
expect(form.attributes.attribute_set.map(&:name)).to eql([:email])
|
110
|
+
expect(form.attributes.model_name).to eql('User')
|
107
111
|
end
|
108
112
|
|
109
113
|
it 'defines a model' do
|
@@ -278,8 +282,8 @@ describe 'Form' do
|
|
278
282
|
end
|
279
283
|
|
280
284
|
it 'copies input' do
|
281
|
-
expect(child_form.
|
282
|
-
expect(child_form.
|
285
|
+
expect(child_form.attributes.attribute_set[:email]).to_not be(nil)
|
286
|
+
expect(child_form.attributes).to_not be(form.attributes)
|
283
287
|
end
|
284
288
|
|
285
289
|
it 'copies model' do
|
data/spec/unit/validator_spec.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe 'Validation' do
|
4
|
-
subject(:validator) { user_validator.new(
|
4
|
+
subject(:validator) { user_validator.new(attributes) }
|
5
5
|
|
6
|
-
let(:
|
6
|
+
let(:user_attrs) do
|
7
7
|
Class.new {
|
8
|
-
include ROM::Model::
|
8
|
+
include ROM::Model::Attributes
|
9
9
|
|
10
10
|
attribute :name, String
|
11
11
|
attribute :email, String
|
@@ -28,24 +28,24 @@ describe 'Validation' do
|
|
28
28
|
end
|
29
29
|
|
30
30
|
describe '#call' do
|
31
|
-
let(:
|
31
|
+
let(:attributes) { {} }
|
32
32
|
|
33
|
-
it 'raises validation error when
|
33
|
+
it 'raises validation error when attributes are not valid' do
|
34
34
|
expect { validator.call }.to raise_error(ROM::Model::ValidationError)
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
38
|
describe "#validate" do
|
39
|
-
let(:
|
39
|
+
let(:attributes) { {} }
|
40
40
|
|
41
|
-
it "sets errors when
|
41
|
+
it "sets errors when attributes are not valid" do
|
42
42
|
validator.validate
|
43
43
|
expect(validator.errors[:name]).to eql(["can't be blank"])
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
47
|
describe ':presence' do
|
48
|
-
let(:
|
48
|
+
let(:attributes) { user_attrs.new(name: '') }
|
49
49
|
|
50
50
|
it 'sets error messages' do
|
51
51
|
expect(validator).to_not be_valid
|
@@ -54,7 +54,7 @@ describe 'Validation' do
|
|
54
54
|
end
|
55
55
|
|
56
56
|
describe ':uniqueness' do
|
57
|
-
let(:
|
57
|
+
let(:attributes) { user_attrs.new(name: 'Jane', email: 'jane@doe.org') }
|
58
58
|
|
59
59
|
before do
|
60
60
|
rom.relations.users.insert(name: 'Jane', email: 'jane@doe.org')
|