rom-rails 0.2.1 → 0.3.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +26 -0
  3. data/CHANGELOG.md +17 -0
  4. data/README.md +4 -0
  5. data/lib/generators/rom/commands/templates/create.rb.erb +10 -0
  6. data/lib/generators/rom/commands/templates/delete.rb.erb +7 -0
  7. data/lib/generators/rom/commands/templates/update.rb.erb +10 -0
  8. data/lib/generators/rom/commands_generator.rb +33 -5
  9. data/lib/generators/rom/form/templates/edit_form.rb.erb +24 -0
  10. data/lib/generators/rom/form/templates/new_form.rb.erb +24 -0
  11. data/lib/generators/rom/form_generator.rb +39 -0
  12. data/lib/generators/rom/mapper/templates/mapper.rb.erb +9 -11
  13. data/lib/generators/rom/mapper_generator.rb +11 -1
  14. data/lib/generators/rom/relation/templates/relation.rb.erb +3 -2
  15. data/lib/generators/rom/relation_generator.rb +16 -1
  16. data/lib/rom-rails.rb +0 -5
  17. data/lib/rom/model.rb +7 -90
  18. data/lib/rom/rails/active_record/configuration.rb +105 -0
  19. data/lib/rom/rails/configuration.rb +4 -27
  20. data/lib/rom/rails/model/form.rb +59 -0
  21. data/lib/rom/rails/model/form/dsl.rb +173 -0
  22. data/lib/rom/rails/model/params.rb +72 -0
  23. data/lib/rom/rails/model/validator.rb +74 -0
  24. data/lib/rom/rails/model/validator/uniqueness_validator.rb +39 -0
  25. data/lib/rom/rails/railtie.rb +65 -29
  26. data/lib/rom/rails/version.rb +1 -1
  27. data/rom-rails.gemspec +3 -1
  28. data/spec/dummy/app/commands/tasks.rb +5 -0
  29. data/spec/dummy/app/commands/users.rb +4 -10
  30. data/spec/dummy/app/controllers/users_controller.rb +30 -0
  31. data/spec/dummy/app/forms/new_user_form.rb +9 -0
  32. data/spec/dummy/app/forms/update_user_form.rb +9 -0
  33. data/spec/dummy/app/forms/user_form.rb +15 -0
  34. data/spec/dummy/app/mappers/users.rb +6 -6
  35. data/spec/dummy/app/relations/tasks.rb +9 -0
  36. data/spec/dummy/app/relations/users.rb +5 -1
  37. data/spec/dummy/app/views/users/edit.html.erb +6 -0
  38. data/spec/dummy/app/views/users/new.html.erb +6 -0
  39. data/spec/dummy/config/routes.rb +5 -1
  40. data/spec/dummy/db/migrate/20141110205016_add_users.rb +2 -0
  41. data/spec/dummy/db/migrate/20150202194440_create_tasks.rb +7 -0
  42. data/spec/dummy/db/schema.rb +8 -8
  43. data/spec/dummy/spec/features/users_spec.rb +30 -0
  44. data/spec/dummy/spec/integration/logger_spec.rb +1 -1
  45. data/spec/dummy/spec/integration/user_commands_spec.rb +2 -18
  46. data/spec/dummy/spec/integration/user_model_mapping_spec.rb +2 -2
  47. data/spec/dummy/spec/integration/user_params_spec.rb +30 -15
  48. data/spec/lib/active_record/configuration_spec.rb +98 -0
  49. data/spec/lib/generators/commands_generator_spec.rb +54 -14
  50. data/spec/lib/generators/form_generator_spec.rb +89 -0
  51. data/spec/lib/generators/mapper_generator_spec.rb +10 -12
  52. data/spec/lib/generators/relation_generator_spec.rb +16 -6
  53. data/spec/spec_helper.rb +1 -1
  54. data/spec/unit/form_spec.rb +297 -0
  55. data/spec/unit/{model_spec.rb → params_spec.rb} +0 -0
  56. data/spec/unit/validator_spec.rb +75 -0
  57. metadata +72 -20
  58. data/lib/generators/rom/commands/templates/commands.rb.erb +0 -15
  59. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  60. data/spec/dummy/app/params/user_params.rb +0 -7
  61. data/spec/dummy/app/validators/user_validator.rb +0 -3
@@ -14,19 +14,17 @@ describe ROM::Generators::MapperGenerator do
14
14
  expect(destination_root).to have_structure {
15
15
  directory 'app' do
16
16
  directory 'mappers' do
17
- file 'users.rb' do
17
+ file 'user_mapper.rb' do
18
18
  contains <<-CONTENT.strip_heredoc
19
- ROM.mappers do
20
-
21
- define(:users) do
22
- # specify model and attributes ie
23
- #
24
- # model User
25
- #
26
- # attribute :name
27
- # attribute :email
28
- end
29
-
19
+ class UserMapper < ROM::Mapper
20
+ # relation :users
21
+ #
22
+ # specify model and attributes ie
23
+ #
24
+ # model User
25
+ #
26
+ # attribute :name
27
+ # attribute :email
30
28
  end
31
29
  CONTENT
32
30
  end
@@ -2,27 +2,30 @@ require 'spec_helper'
2
2
 
3
3
  require 'generators/rom/relation_generator'
4
4
 
5
- describe ROM::Generators::RelationGenerator do
5
+ describe ROM::Generators::RelationGenerator, type: :generator do
6
6
  destination File.expand_path('../../../../tmp', __FILE__)
7
7
 
8
- before(:all) do
8
+ before(:each) do
9
9
  prepare_destination
10
- run_generator ['users']
11
10
  end
12
11
 
13
12
  specify do
13
+ run_generator ['users']
14
+ default_adapter = ROM.adapters.keys.first
15
+
14
16
  expect(destination_root).to have_structure {
15
17
  directory 'app' do
16
18
  directory 'relations' do
17
- file 'users.rb' do
19
+ file 'users_relation.rb' do
18
20
  contains <<-CONTENT.strip_heredoc
19
- ROM.relation(:users) do
21
+ class UsersRelation < ROM::Relation[:#{default_adapter}]
22
+ dataset :users
23
+
20
24
  # define your methods here ie:
21
25
  #
22
26
  # def all
23
27
  # select(:id, :name).order(:id)
24
28
  # end
25
- #
26
29
  end
27
30
  CONTENT
28
31
  end
@@ -30,4 +33,11 @@ describe ROM::Generators::RelationGenerator do
30
33
  end
31
34
  }
32
35
  end
36
+
37
+ specify "with given adapter" do
38
+ run_generator ['users', '--adapter=memory']
39
+
40
+ relation = File.read(File.join(destination_root, 'app', 'relations', 'users_relation.rb'))
41
+ expect(relation).to include("class UsersRelation < ROM::Relation[:memory]")
42
+ end
33
43
  end
data/spec/spec_helper.rb CHANGED
@@ -25,5 +25,5 @@ RSpec.configure do |config|
25
25
  end
26
26
 
27
27
  def rom
28
- Rails.application.config.rom.env
28
+ ROM.env
29
29
  end
@@ -0,0 +1,297 @@
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 = {
29
+ 'name' => 'Jane',
30
+ 'hash' => { 'one' => '', 'two' => 2 },
31
+ 'array' => [{ 'three' => '', 'four' => 4 }, 5]
32
+ }
33
+
34
+ form_object = form.build(input)
35
+
36
+ expect(form_object.params).to eql(
37
+ name: 'Jane', hash: { two: 2 }, array: [{ four: 4 }, 5]
38
+ )
39
+ end
40
+ end
41
+
42
+ describe '.commands' do
43
+ it 'builds its own command registry' do
44
+ form = Class.new(ROM::Model::Form) {
45
+ inject_commands_for :tasks
46
+ commands users: :create
47
+ input { attribute :name }
48
+ validations { validates :name, presence: true }
49
+
50
+ def commit!
51
+ users.try { users.create.call(params) }
52
+ end
53
+ }
54
+
55
+ form_object = form.build(name: '').save
56
+
57
+ expect(form_object).not_to be_success
58
+ expect(form_object.errors[:name]).to include("can't be blank")
59
+ expect(rom.relations.users.first).to be(nil)
60
+
61
+ form_object = form.build(name: 'Jane').save
62
+
63
+ expect(form_object).to be_success
64
+ expect(rom.relations.users.first).to include(name: 'Jane')
65
+
66
+ expect(form_object.tasks).to be(rom.command(:tasks))
67
+ end
68
+ end
69
+
70
+ describe '.key' do
71
+ it 'returns default key' do
72
+ expect(form.key).to eql([:id])
73
+ expect(form.new({}, { id: 312 }).to_key).to eql([312])
74
+ end
75
+
76
+ it 'sets a custom composite key' do
77
+ form = Class.new(ROM::Model::Form) do
78
+ def self.name
79
+ 'UserForm'
80
+ end
81
+
82
+ key :foo_id, :bar_id
83
+
84
+ input do
85
+ set_model_name 'User'
86
+
87
+ attribute :email, String
88
+ end
89
+ end
90
+
91
+ expect(form.key).to eql([:foo_id, :bar_id])
92
+ expect(form.new({}, { foo_id: 312, bar_id: 132 }).to_key).to eql([312, 132])
93
+ end
94
+ end
95
+
96
+ describe '.model_name' do
97
+ it 'delegates to Params.model_name' do
98
+ expect(form.model_name).to be(form.params.model_name)
99
+ end
100
+ end
101
+
102
+ describe 'input DSL' do
103
+ it 'defines params handler' do
104
+ expect(form.const_defined?(:Params)).to be(true)
105
+ expect(form.params.attribute_set.map(&:name)).to eql([:email])
106
+ expect(form.params.model_name).to eql('User')
107
+ end
108
+
109
+ it 'defines a model' do
110
+ expect(form.const_defined?(:Model)).to be(true)
111
+ expect(form.model.attribute_set.map(&:name)).to match_array([:id, :email])
112
+ end
113
+
114
+ it 'raises error when attribute is in conflict with form interface' do
115
+ expect {
116
+ Class.new(ROM::Model::Form) do
117
+ input do
118
+ attribute :commit!
119
+ end
120
+ end
121
+ }.to raise_error(ArgumentError, /commit! attribute is in conflict/)
122
+ end
123
+ end
124
+
125
+ describe 'validator DSL' do
126
+ it 'defines validator' do
127
+ expect(form.const_defined?(:Validator)).to be(true)
128
+
129
+ expect(form.validator).not_to be(nil)
130
+
131
+ expect { form.validator.call(email: 'jane@doe') }.not_to raise_error
132
+
133
+ expect { form.validator.call(email: '') }.to raise_error(
134
+ ROM::Model::ValidationError
135
+ )
136
+ end
137
+ end
138
+
139
+ describe '#model_name' do
140
+ it 'delegates to model' do
141
+ form_object = form.build
142
+ expect(form_object.model_name).to be(form_object.model.model_name)
143
+ end
144
+ end
145
+
146
+ describe '#persisted?' do
147
+ it 'delegates to model' do
148
+ form_object = form.build
149
+ expect(form_object).not_to be_persisted
150
+ expect(form_object.persisted?).to be(form_object.model.persisted?)
151
+
152
+ form_object = form.build({}, { id: 1 })
153
+ expect(form_object).to be_persisted
154
+ expect(form_object.persisted?).to be(form_object.model.persisted?)
155
+ end
156
+ end
157
+
158
+ describe '#to_model' do
159
+ context 'with a new model' do
160
+ it 'returns model object without key set' do
161
+ model = form.build(email: 'jane@doe').to_model
162
+
163
+ expect(model.id).to be(nil)
164
+ expect(model.model_name).to eql('User')
165
+ expect(model.to_key).to eql([])
166
+ expect(model.to_param).to be(nil)
167
+ expect(model).not_to be_persisted
168
+ end
169
+ end
170
+
171
+ context 'with a persisted model' do
172
+ it 'returns model object with key set' do
173
+ model = form.build({ email: 'jane@doe' }, { id: 312 }).to_model
174
+
175
+ expect(model.id).to be(312)
176
+ expect(model.model_name).to eql('User')
177
+ expect(model.to_key).to eql([312])
178
+ expect(model.to_param).to eql('312')
179
+ expect(model).to be_persisted
180
+ end
181
+ end
182
+ end
183
+
184
+ describe '#save' do
185
+ it 'commits the form without extra args' do
186
+ result = form.build({}).save.result
187
+ expect(result).to eql('it works []')
188
+ end
189
+
190
+ it 'commits the form with extra args' do
191
+ result = form.build({}).save(1, 2, 3).result
192
+ expect(result).to eql('it works [1, 2, 3]')
193
+ end
194
+ end
195
+
196
+ describe "#errors" do
197
+ context "with a new model" do
198
+ it "exposes an activemodel compatible error" do
199
+ errors = form.build({}).errors
200
+
201
+ expect(errors).to be_instance_of(
202
+ ActiveModel::Errors
203
+ )
204
+
205
+ expect(errors[:email]).to eq []
206
+ end
207
+ end
208
+ end
209
+
210
+ describe "#attributes" do
211
+ it "returns processed attributes" do
212
+ form = Class.new(ROM::Model::Form) do
213
+ def self.name
214
+ 'UserForm'
215
+ end
216
+
217
+ key :foo_id, :bar_id
218
+
219
+ input do
220
+ set_model_name 'User'
221
+
222
+ attribute :uid, Integer
223
+ end
224
+ end
225
+
226
+ form_object = form.build(uid: "12345")
227
+ expect(form_object.attributes[:uid]).to eq 12_345
228
+ end
229
+ end
230
+
231
+ describe "#validate!" do
232
+ it "runs validations and assigns errors" do
233
+ form_object = form.build({})
234
+ form_object.validate!
235
+
236
+ expect(form_object.errors[:email]).to include "can't be blank"
237
+ end
238
+
239
+ it "uses processed parameters" do
240
+ form = Class.new(ROM::Model::Form) do
241
+ def self.name
242
+ 'UserForm'
243
+ end
244
+
245
+ key :foo_id, :bar_id
246
+
247
+ input do
248
+ set_model_name 'User'
249
+
250
+ attribute :email, String
251
+ attribute :country, String, default: "Unkown"
252
+ end
253
+
254
+ validations do
255
+ validates :email, presence: true
256
+ validates :country, presence: true
257
+ end
258
+ end
259
+
260
+ form_object = form.build(uid: "12345")
261
+ form_object.validate!
262
+
263
+ expect(form_object.errors[:country]).to be_blank
264
+ end
265
+ end
266
+
267
+ describe 'inheritance' do
268
+ let(:child_form) do
269
+ Class.new(form) do
270
+ def self.name
271
+ "NewUserForm"
272
+ end
273
+ end
274
+ end
275
+
276
+ it 'copies model_name' do
277
+ expect(child_form.model_name.name).to eql(form.model_name.name)
278
+ end
279
+
280
+ it 'copies input' do
281
+ expect(child_form.params.attribute_set[:email]).to_not be(nil)
282
+ expect(child_form.params).to_not be(form.params)
283
+ end
284
+
285
+ it 'copies model' do
286
+ expect(child_form.model.attribute_set[:email]).to_not be(nil)
287
+ expect(child_form.model).to_not be(form.model)
288
+ end
289
+
290
+ it 'copies validator' do
291
+ expect(child_form.validator.validators.first).to be_instance_of(
292
+ ActiveModel::Validations::PresenceValidator
293
+ )
294
+ expect(child_form.validator).to_not be(form.validator)
295
+ end
296
+ end
297
+ end
File without changes
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Validation' do
4
+ subject(:validator) { user_validator.new(params) }
5
+
6
+ let(:user_params) do
7
+ Class.new {
8
+ include ROM::Model::Params
9
+
10
+ attribute :name, String
11
+ attribute :email, String
12
+ }
13
+ end
14
+
15
+ let(:user_validator) do
16
+ Class.new {
17
+ include ROM::Model::Validator
18
+
19
+ relation :users
20
+
21
+ validates :name, presence: true, uniqueness: { message: 'TAKEN!' }
22
+ validates :email, uniqueness: true
23
+
24
+ def self.name
25
+ 'UserValidator'
26
+ end
27
+ }
28
+ end
29
+
30
+ describe '#call' do
31
+ let(:params) { {} }
32
+
33
+ it 'raises validation error when params are not valid' do
34
+ expect { validator.call }.to raise_error(ROM::Model::ValidationError)
35
+ end
36
+ end
37
+
38
+ describe "#validate" do
39
+ let(:params) { {} }
40
+
41
+ it "sets errors when params are not valid" do
42
+ validator.validate
43
+ expect(validator.errors[:name]).to eql(["can't be blank"])
44
+ end
45
+ end
46
+
47
+ describe ':presence' do
48
+ let(:params) { user_params.new(name: '') }
49
+
50
+ it 'sets error messages' do
51
+ expect(validator).to_not be_valid
52
+ expect(validator.errors[:name]).to eql(["can't be blank"])
53
+ end
54
+ end
55
+
56
+ describe ':uniqueness' do
57
+ let(:params) { user_params.new(name: 'Jane', email: 'jane@doe.org') }
58
+
59
+ before do
60
+ rom.relations.users.insert(name: 'Jane', email: 'jane@doe.org')
61
+ end
62
+
63
+ it 'sets default error messages' do
64
+ expect(validator).to_not be_valid
65
+ expect(validator.errors[:email]).to eql(['has already been taken'])
66
+ end
67
+
68
+ it 'sets custom error messages' do
69
+ rom.relations.users.insert(name: 'Jane', email: 'jane@doe.org')
70
+
71
+ expect(validator).to_not be_valid
72
+ expect(validator.errors[:name]).to eql(['TAKEN!'])
73
+ end
74
+ end
75
+ end