rom-rails 0.9.0 → 1.0.0.beta1

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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +2 -0
  3. data/.travis.yml +1 -0
  4. data/CHANGELOG.md +14 -0
  5. data/Gemfile +8 -5
  6. data/lib/generators/rom/commands/templates/create.rb.erb +5 -7
  7. data/lib/generators/rom/commands/templates/update.rb.erb +5 -7
  8. data/lib/generators/rom/relation/templates/relation.rb.erb +6 -4
  9. data/lib/rom-rails.rb +0 -1
  10. data/lib/rom/rails/configuration.rb +0 -2
  11. data/lib/rom/rails/version.rb +1 -1
  12. data/rom-rails.gemspec +2 -4
  13. data/spec/dummy/app/commands/create_user.rb +10 -0
  14. data/spec/dummy/app/commands/update_user.rb +9 -0
  15. data/spec/dummy/app/controllers/users_controller.rb +12 -8
  16. data/spec/dummy/app/forms/user_form.rb +29 -9
  17. data/spec/dummy/app/mappers/task_mapper.rb +1 -1
  18. data/spec/dummy/app/mappers/user_mapper.rb +1 -1
  19. data/spec/dummy/app/models/user.rb +1 -1
  20. data/spec/dummy/app/relations/dummy_relation.rb +2 -1
  21. data/spec/dummy/app/relations/tasks.rb +2 -0
  22. data/spec/dummy/app/relations/users.rb +2 -0
  23. data/spec/dummy/lib/rom/test_adapter.rb +1 -1
  24. data/spec/features/users_spec.rb +1 -3
  25. data/spec/integration/activerecord_setup.rb +1 -1
  26. data/spec/integration/initializer_spec.rb +1 -3
  27. data/spec/integration/logger_spec.rb +1 -3
  28. data/spec/integration/user_commands_spec.rb +7 -7
  29. data/spec/integration/user_model_mapping_spec.rb +2 -4
  30. data/spec/lib/active_record/configuration_spec.rb +1 -2
  31. data/spec/lib/generators/commands_generator_spec.rb +7 -17
  32. data/spec/lib/generators/mapper_generator_spec.rb +1 -3
  33. data/spec/lib/generators/relation_generator_spec.rb +4 -8
  34. data/spec/lib/generators/repository_generator_spec.rb +1 -3
  35. data/spec/spec_helper.rb +1 -1
  36. metadata +12 -61
  37. data/lib/generators/rom/form/templates/base_form.rb.erb +0 -17
  38. data/lib/generators/rom/form/templates/edit_form.rb.erb +0 -20
  39. data/lib/generators/rom/form/templates/new_form.rb.erb +0 -20
  40. data/lib/generators/rom/form_generator.rb +0 -47
  41. data/lib/rom/rails/model/form.rb +0 -173
  42. data/lib/rom/rails/model/form/class_interface.rb +0 -457
  43. data/lib/rom/rails/model/form/error_proxy.rb +0 -53
  44. data/spec/dummy/app/forms/new_user_form.rb +0 -13
  45. data/spec/dummy/app/forms/update_user_form.rb +0 -11
  46. data/spec/integration/form_with_injected_commands_spec.rb +0 -37
  47. data/spec/integration/new_user_form_spec.rb +0 -19
  48. data/spec/lib/generators/form_generator_spec.rb +0 -140
  49. data/spec/unit/form_spec.rb +0 -366
@@ -1,53 +0,0 @@
1
- module ROM
2
- module Model
3
- class Form
4
- # Proxy for form errors
5
- #
6
- # This simple proxy forwards most messages to a wrapped
7
- # ActiveModel::Errors object
8
- #
9
- # @api private
10
- class ErrorProxy < SimpleDelegator
11
- # @api private
12
- def initialize
13
- super ActiveModel::Errors.new([])
14
- end
15
-
16
- # update the current errors
17
- #
18
- # @param error [ActiveModel::Errors, ROM::Model::ValidatonError, object]
19
- #
20
- # When the argument is an AM Error object, or our wrapper around one,
21
- # replace the wrapped object. Otherwise, add an error to the current
22
- # messages
23
- #
24
- # @return [self]
25
- #
26
- # @api private
27
- def set(error)
28
- case error
29
- when ActiveModel::Errors
30
- __setobj__ error
31
- when ROM::Model::ValidationError
32
- __setobj__ error.errors
33
- when nil
34
- # do nothing
35
- else
36
- add(:base, "a database error prevented saving this form")
37
- end
38
-
39
- self
40
- end
41
-
42
- # Has the command succeeded?
43
- #
44
- # @return [Boolean]
45
- #
46
- # @api public
47
- def success?
48
- !present?
49
- end
50
- end
51
- end
52
- end
53
- end
@@ -1,13 +0,0 @@
1
- class NewUserForm < UserForm
2
- commands users: :create
3
-
4
- mappings users: :entity
5
-
6
- input do
7
- timestamps(:created_at)
8
- end
9
-
10
- def commit!
11
- users.try { users.create.call(attributes) }
12
- end
13
- end
@@ -1,11 +0,0 @@
1
- class UpdateUserForm < UserForm
2
- commands users: :update
3
-
4
- input do
5
- timestamps(:updated_at)
6
- end
7
-
8
- def commit!
9
- users.try { users.update.by_id(id).call(attributes) }
10
- end
11
- end
@@ -1,37 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe 'Form with injected commands' do
4
- subject(:form) { form_class.build(params) }
5
-
6
- let(:params) { { title: 'Task one' } }
7
-
8
- let(:form_class) do
9
- Class.new(ROM::Model::Form) do
10
- commands users: :create, tasks: :create
11
-
12
- inject_commands_for :tasks
13
-
14
- mappings tasks: :entity
15
-
16
- input do
17
- set_model_name 'Task'
18
-
19
- attribute :title
20
- end
21
-
22
- def commit!
23
- tasks.create[attributes]
24
- end
25
- end
26
- end
27
-
28
- it 'auto-maps result using injected commands' do
29
- form.save
30
-
31
- value = form.result
32
-
33
- expect(value).to be_a(Task)
34
- expect(value.id).to_not be(nil)
35
- expect(value.title).to eql('Task one')
36
- end
37
- end
@@ -1,19 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe NewUserForm do
4
- subject(:form) { NewUserForm.build(params) }
5
-
6
- let(:params) do
7
- { name: 'Jane', email: 'jane@doe.org' }
8
- end
9
-
10
- describe '#save' do
11
- it 'persists attributes and auto-map result to entity object' do
12
- form.save
13
-
14
- user = form.result.value
15
-
16
- expect(user).to eql(User.new(id: 1, name: 'Jane', email: 'jane@doe.org'))
17
- end
18
- end
19
- end
@@ -1,140 +0,0 @@
1
- require 'spec_helper'
2
-
3
- require 'generators/rom/form_generator'
4
-
5
- describe ROM::Generators::FormGenerator do
6
- destination File.expand_path('../../../../tmp', __FILE__)
7
-
8
- before(:each) do
9
- prepare_destination
10
- end
11
-
12
- shared_examples_for "generates a base user form" do
13
- it "populates a base form file" do
14
- expect(destination_root).to have_structure {
15
- directory 'app' do
16
- directory 'forms' do
17
- file 'user_form.rb' do
18
- contains <<-CONTENT.strip_heredoc
19
- class UserForm < ROM::Model::Form
20
-
21
- input do
22
- set_model_name 'User'
23
-
24
- # define always-present form input attributes
25
- # attribute :name, String
26
- end
27
-
28
- validations do
29
- relation :users
30
-
31
- # Add invariant form validations
32
- # validates :name, presence: true
33
- end
34
-
35
- end
36
- CONTENT
37
- end
38
- end
39
- end
40
- }
41
- end
42
- end
43
-
44
- shared_examples_for "generates a create user form" do
45
- it "populates a create form file" do
46
- expect(destination_root).to have_structure {
47
- directory 'app' do
48
- directory 'forms' do
49
- file 'new_user_form.rb' do
50
- contains <<-CONTENT.strip_heredoc
51
- class NewUserForm < UserForm
52
- commands users: :create
53
-
54
- input do
55
- # define form input attributes
56
- # attribute :name, String
57
-
58
- timestamps
59
- end
60
-
61
- validations do
62
- # Add form validations
63
- # validates :name, presence: true
64
- end
65
-
66
- def commit!
67
- users.try { users.create.call(attributes) }
68
- end
69
-
70
- end
71
- CONTENT
72
- end
73
- end
74
- end
75
- }
76
- end
77
- end
78
-
79
- shared_examples_for "generates an edit user form" do
80
- it "populates a edit form file" do
81
- expect(destination_root).to have_structure {
82
- directory 'app' do
83
- directory 'forms' do
84
- file 'edit_user_form.rb' do
85
- contains <<-CONTENT.strip_heredoc
86
- class EditUserForm < UserForm
87
- commands users: :update
88
-
89
- input do
90
- # define form input attributes
91
- # attribute :name, String
92
-
93
- timestamps :updated_at
94
- end
95
-
96
- validations do
97
- # Add form validations
98
- # validates :name, presence: true
99
- end
100
-
101
- def commit!
102
- users.try { users.update.by_id(id).set(attributes) }
103
- end
104
-
105
- end
106
- CONTENT
107
- end
108
- end
109
- end
110
- }
111
- end
112
- end
113
-
114
- describe "rom:form users" do
115
- before do
116
- run_generator ['users']
117
- end
118
-
119
- it_should_behave_like "generates a create user form"
120
- it_should_behave_like "generates an edit user form"
121
- end
122
-
123
- describe "rom:form users --command=create" do
124
- before do
125
- run_generator ['users', '--command=create']
126
- end
127
-
128
- it_should_behave_like "generates a base user form"
129
- it_should_behave_like "generates a create user form"
130
- end
131
-
132
- describe "rom:form users --command=update" do
133
- before do
134
- run_generator ['users', '--command=update']
135
- end
136
-
137
- it_should_behave_like "generates a base user form"
138
- it_should_behave_like "generates an edit user form"
139
- end
140
- end
@@ -1,366 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe 'Form' do
4
- subject(:form) do
5
- Class.new(ROM::Model::Form) do
6
- def self.name
7
- 'UserForm'
8
- end
9
-
10
- input do
11
- set_model_name 'User'
12
-
13
- attribute :email, String
14
- end
15
-
16
- validations do
17
- validates :email, presence: true
18
- end
19
-
20
- def commit!(*args)
21
- "it works #{args.inspect}"
22
- end
23
- end
24
- end
25
-
26
- describe '.build' do
27
- it 'rejects blank strings from params' do
28
- input = { 'name' => '' }
29
-
30
- form_object = form.build(input)
31
-
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')
43
- end
44
- end
45
-
46
- describe '.commands' do
47
- it 'builds its own command registry' do
48
- form = Class.new(ROM::Model::Form) {
49
- inject_commands_for :tasks
50
- commands users: :create
51
- input { attribute :name }
52
- validations { validates :name, presence: true }
53
-
54
- def commit!
55
- users.try { users.create.call(attributes) }
56
- end
57
- }
58
-
59
- form_object = form.build(name: '').save
60
-
61
- expect(form_object).not_to be_success
62
- expect(form_object.errors[:name]).to include("can't be blank")
63
- expect(rom.relations.users.first).to be(nil)
64
-
65
- form_object = form.build(name: 'Jane').save
66
-
67
- expect(form_object).to be_success
68
- expect(rom.relations.users.first).to include(name: 'Jane')
69
-
70
- expect(form_object.tasks).to_not be(nil)
71
- end
72
- end
73
-
74
- describe '.key' do
75
- it 'returns default key' do
76
- expect(form.key).to eql([:id])
77
- expect(form.new({}, { id: 312 }).to_key).to eql([312])
78
- end
79
-
80
- it 'sets a custom composite key' do
81
- form = Class.new(ROM::Model::Form) do
82
- def self.name
83
- 'UserForm'
84
- end
85
-
86
- key :foo_id, :bar_id
87
-
88
- input do
89
- set_model_name 'User'
90
-
91
- attribute :email, String
92
- end
93
- end
94
-
95
- expect(form.key).to eql([:foo_id, :bar_id])
96
- expect(form.new({}, { foo_id: 312, bar_id: 132 }).to_key).to eql([312, 132])
97
- end
98
- end
99
-
100
- describe '.model_name' do
101
- it 'delegates to Attributes.model_name' do
102
- expect(form.model_name).to be(form.attributes.model_name)
103
- end
104
- end
105
-
106
- describe 'input DSL' do
107
- it 'defines params handler' do
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')
111
- end
112
-
113
- it 'defines a model' do
114
- expect(form.const_defined?(:Model)).to be(true)
115
- expect(form.model.attribute_set.map(&:name)).to match_array([:id, :email])
116
- end
117
-
118
- it 'raises error when attribute is in conflict with form interface' do
119
- expect {
120
- Class.new(ROM::Model::Form) do
121
- input do
122
- attribute :commit!
123
- end
124
- end
125
- }.to raise_error(ArgumentError, /commit! attribute is in conflict/)
126
- end
127
- end
128
-
129
- describe 'validator DSL' do
130
- it 'defines validator' do
131
- expect(form.const_defined?(:Validator)).to be(true)
132
-
133
- expect(form.validator).not_to be(nil)
134
-
135
- expect { form.validator.call(email: 'jane@doe') }.not_to raise_error
136
-
137
- expect { form.validator.call(email: '') }.to raise_error(
138
- ROM::Model::ValidationError
139
- )
140
- end
141
- end
142
-
143
- describe '#model_name' do
144
- it 'delegates to model' do
145
- form_object = form.build
146
- expect(form_object.model_name).to be(form_object.model.model_name)
147
- end
148
- end
149
-
150
- describe '#persisted?' do
151
- it 'delegates to model' do
152
- form_object = form.build
153
- expect(form_object).not_to be_persisted
154
- expect(form_object.persisted?).to be(form_object.model.persisted?)
155
-
156
- form_object = form.build({}, { id: 1 })
157
- expect(form_object).to be_persisted
158
- expect(form_object.persisted?).to be(form_object.model.persisted?)
159
- end
160
- end
161
-
162
- describe '#to_model' do
163
- context 'with a new model' do
164
- it 'returns model object without key set' do
165
- model = form.build(email: 'jane@doe').to_model
166
-
167
- expect(model.id).to be(nil)
168
- expect(model.model_name).to eql('User')
169
- expect(model.to_key).to eql([])
170
- expect(model.to_param).to be(nil)
171
- expect(model).not_to be_persisted
172
- end
173
- end
174
-
175
- context 'with a persisted model' do
176
- it 'returns model object with key set' do
177
- model = form.build({ email: 'jane@doe' }, { id: 312 }).to_model
178
-
179
- expect(model.id).to be(312)
180
- expect(model.model_name).to eql('User')
181
- expect(model.to_key).to eql([312])
182
- expect(model.to_param).to eql('312')
183
- expect(model).to be_persisted
184
- end
185
- end
186
- end
187
-
188
- describe '#save' do
189
- it 'commits the form without extra args' do
190
- result = form.build({email: 'jdoe@example.com'}).save.result
191
- expect(result).to eql('it works []')
192
- end
193
-
194
- it 'commits the form with extra args' do
195
- result = form.build({email: 'jdoe@example.com'}).save(1, 2, 3).result
196
- expect(result).to eql('it works [1, 2, 3]')
197
- end
198
- end
199
-
200
- describe "#errors" do
201
- context "with a new model" do
202
- it "exposes an activemodel compatible error" do
203
- errors = form.build({}).errors
204
-
205
- expect(errors).to respond_to(:[])
206
- expect(errors).to respond_to(:empty?)
207
- expect(errors).to respond_to(:blank?)
208
-
209
- expect(errors[:email]).to eq []
210
- end
211
- end
212
-
213
- it "recovers from database errors" do
214
- form = Class.new(ROM::Model::Form) do
215
- commands users: :create
216
-
217
- input do
218
- set_model_name 'User'
219
-
220
- attribute :email, String
221
- end
222
-
223
- def commit!(*)
224
- users.try {
225
- raise ROM::SQL::ConstraintError, RuntimeError.new("duplicate key")
226
- }
227
- end
228
- end
229
-
230
- expect {
231
- form.build(email: 'test@example.com').save
232
- }.to raise_error(ROM::SQL::ConstraintError)
233
- end
234
- end
235
-
236
- describe "#attributes" do
237
- it "returns processed attributes" do
238
- form = Class.new(ROM::Model::Form) do
239
- def self.name
240
- 'UserForm'
241
- end
242
-
243
- key :foo_id, :bar_id
244
-
245
- input do
246
- set_model_name 'User'
247
-
248
- attribute :uid, Integer
249
- end
250
- end
251
-
252
- form_object = form.build(uid: "12345")
253
- expect(form_object.attributes[:uid]).to eq 12_345
254
- end
255
- end
256
-
257
- describe "#validate!" do
258
- it "runs validations and assigns errors" do
259
- form_object = form.build({})
260
- form_object.validate!
261
-
262
- expect(form_object.errors[:email]).to include "can't be blank"
263
- end
264
-
265
- it "uses processed parameters" do
266
- form = Class.new(ROM::Model::Form) do
267
- def self.name
268
- 'UserForm'
269
- end
270
-
271
- key :foo_id, :bar_id
272
-
273
- input do
274
- set_model_name 'User'
275
-
276
- attribute :email, String
277
- attribute :country, String, default: "Unkown"
278
- end
279
-
280
- validations do
281
- validates :email, presence: true
282
- validates :country, presence: true
283
- end
284
- end
285
-
286
- form_object = form.build(uid: "12345")
287
- form_object.validate!
288
-
289
- expect(form_object.errors[:country]).to be_blank
290
- end
291
- end
292
-
293
- describe 'inheritance' do
294
- let(:child_form) do
295
- Class.new(form) do
296
- def self.name
297
- "NewUserForm"
298
- end
299
- end
300
- end
301
-
302
- it 'copies model_name' do
303
- expect(child_form.model_name.name).to eql(form.model_name.name)
304
- end
305
-
306
- it 'copies input' do
307
- expect(child_form.attributes.attribute_set[:email]).to_not be(nil)
308
- expect(child_form.attributes).to_not be(form.attributes)
309
- end
310
-
311
- it 'expands input' do
312
- child_form = Class.new(form) do
313
- def self.name
314
- "NewUserForm"
315
- end
316
-
317
- input do
318
- attribute :login, String
319
- end
320
- end
321
-
322
- expect(child_form.attributes.attribute_set[:login]).to_not be(nil)
323
- expect(child_form.attributes.attribute_set[:email]).to_not be(nil)
324
-
325
- expect(child_form.attributes).to_not be(form.attributes)
326
- end
327
-
328
- it 'copies model' do
329
- expect(child_form.model.attribute_set[:email]).to_not be(nil)
330
- expect(child_form.model).to_not be(form.model)
331
- end
332
-
333
- it 'copies validator' do
334
- expect(child_form.validator.validators.first).to be_instance_of(
335
- ActiveModel::Validations::PresenceValidator
336
- )
337
- expect(child_form.validator).to_not be(form.validator)
338
- end
339
-
340
- it "expands existing validators" do
341
- child_form = Class.new(form) do
342
- def self.name
343
- "NewUserForm"
344
- end
345
-
346
- input do
347
- attribute :login, String
348
- end
349
-
350
- validations do
351
- validates :login, length: { minimum: 4 }
352
- end
353
- end
354
-
355
- expect(child_form.validator.validators.first).to be_instance_of(
356
- ActiveModel::Validations::PresenceValidator
357
- )
358
-
359
- expect(child_form.validator.validators.last).to be_instance_of(
360
- ActiveModel::Validations::LengthValidator
361
- )
362
-
363
- expect(child_form.validator).to_not be(form.validator)
364
- end
365
- end
366
- end