mini_form 0.1.0 → 0.2.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 +28 -0
- data/README.md +37 -4
- data/lib/mini_form/errors.rb +7 -0
- data/lib/mini_form/model.rb +38 -9
- data/lib/mini_form/version.rb +1 -1
- data/spec/mini_form_spec.rb +71 -11
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6d0c0c470b74ebc5e81006fa9f4f226de8d821d6
|
4
|
+
data.tar.gz: 38393dfb6c142a1f85dca47a2aa16072a63f657f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1f8c4900a91ceedd1b9f7c12b73e5b2fc30f033fd47783ae792a4c9e8dbb3f0bae93c65953da6ddebf1bbc75e3bb8c4484e863e33925b67672f11246e4b094b6
|
7
|
+
data.tar.gz: 5a3a73ad3547ba949a1900918a1cdcfefc73c8bf77d0764d89fa0858c6fe8ae075a0493066f80b65d62429160e5a93d2734303d75fcc66d8b8746596d3455730
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,33 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## Version 0.2.0
|
4
|
+
|
5
|
+
* Don't expose model name on `model`. _(security fix)_
|
6
|
+
|
7
|
+
* Included `ActiveModel::Validations::Callbacks` to `MiniForm::Model`
|
8
|
+
|
9
|
+
* Added read option to `model`:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
class EditProfile
|
13
|
+
include MiniForm::Model
|
14
|
+
|
15
|
+
model :user, attributes: %i(email name), read:%(id)
|
16
|
+
end
|
17
|
+
|
18
|
+
profile = EditProfile.new(user: user)
|
19
|
+
profile.id
|
20
|
+
profile.id = 1 # raises NoMethodError
|
21
|
+
```
|
22
|
+
|
23
|
+
|
24
|
+
* MiniForm::Model can be inherited
|
25
|
+
* Added `assigment` callbacks, called when attributes are assigned
|
26
|
+
* Added `assign_attributes` alias to `attributes=`
|
27
|
+
* Exposed `errors` on MiniForm::InvalidForm
|
28
|
+
* Added descriptive message MiniForm::InvalidForm
|
29
|
+
* Made `.attribute_names` public
|
30
|
+
|
3
31
|
## Version 0.1.0
|
4
32
|
|
5
33
|
* Initial release
|
data/README.md
CHANGED
@@ -46,7 +46,7 @@ class ProductsController < ApplicationController
|
|
46
46
|
@product = ProductForm.new
|
47
47
|
|
48
48
|
if @product.update(product_params)
|
49
|
-
redirect_to product_path(product.id)
|
49
|
+
redirect_to product_path(@product.id)
|
50
50
|
else
|
51
51
|
render :edit
|
52
52
|
end
|
@@ -130,7 +130,7 @@ Combines delegated attributes and nested validation into a single call.
|
|
130
130
|
class SignUpForm
|
131
131
|
include MiniForm::Model
|
132
132
|
|
133
|
-
|
133
|
+
model :user, attributes: %i(name email)
|
134
134
|
model :account, attributes: %i(company_name plan)
|
135
135
|
|
136
136
|
def initialize
|
@@ -147,13 +147,13 @@ end
|
|
147
147
|
|
148
148
|
### Auto saving nested models
|
149
149
|
|
150
|
-
|
150
|
+
Most of the time `perform` is just calling `save!`. We can avoid this by using `model`'s `save` option.
|
151
151
|
|
152
152
|
```ruby
|
153
153
|
class SignUpForm
|
154
154
|
include MiniForm::Model
|
155
155
|
|
156
|
-
|
156
|
+
model :user, attributes: %i(name email), save: true
|
157
157
|
model :account, attributes: %i(company_name plan), save: true
|
158
158
|
|
159
159
|
def initialize
|
@@ -194,6 +194,27 @@ class SignUpForm
|
|
194
194
|
end
|
195
195
|
```
|
196
196
|
|
197
|
+
### Delegating model attributes
|
198
|
+
|
199
|
+
```ruby
|
200
|
+
class SignUpForm
|
201
|
+
include MiniForm::Model
|
202
|
+
|
203
|
+
model :user, attributes: %i(name email), read: %i(id)
|
204
|
+
|
205
|
+
def initialize
|
206
|
+
@user = User.new account: @account
|
207
|
+
end
|
208
|
+
end
|
209
|
+
```
|
210
|
+
|
211
|
+
```
|
212
|
+
form = SignUpForm.new
|
213
|
+
form.update! form_params
|
214
|
+
form.id # => delegates to `user.id`
|
215
|
+
form.id = 42 # => raises `NoMethodError`
|
216
|
+
```
|
217
|
+
|
197
218
|
### Methods
|
198
219
|
|
199
220
|
<table>
|
@@ -209,6 +230,10 @@ end
|
|
209
230
|
<td>.attributes</td>
|
210
231
|
<td>Defines an attribute, it can delegate to sub object</td>
|
211
232
|
</tr>
|
233
|
+
<tr>
|
234
|
+
<td>.attribute_names</td>
|
235
|
+
<td>Returns list of attribute names</td>
|
236
|
+
</tr>
|
212
237
|
<tr>
|
213
238
|
<td>#initialize</td>
|
214
239
|
<td>Meant to be overwritten. By defaults calls `attributes=`</td>
|
@@ -241,6 +266,14 @@ end
|
|
241
266
|
<td>#after_update</td>
|
242
267
|
<td>Meant to be overwritten.</td>
|
243
268
|
</tr>
|
269
|
+
<tr>
|
270
|
+
<td>#before_assigment</td>
|
271
|
+
<td>Meant to be overwritten.</td>
|
272
|
+
</tr>
|
273
|
+
<tr>
|
274
|
+
<td>#after_assigment</td>
|
275
|
+
<td>Meant to be overwritten.</td>
|
276
|
+
</tr>
|
244
277
|
<tr>
|
245
278
|
<td>#transaction</td>
|
246
279
|
<td>If ActiveRecord is available, wraps `perform` in transaction.</td>
|
data/lib/mini_form/errors.rb
CHANGED
data/lib/mini_form/model.rb
CHANGED
@@ -3,9 +3,10 @@ require 'active_model'
|
|
3
3
|
|
4
4
|
module MiniForm
|
5
5
|
module Model
|
6
|
-
def self.included(base)
|
6
|
+
def self.included(base) # rubocop:disable MethodLength
|
7
7
|
base.class_eval do
|
8
8
|
include ActiveModel::Validations
|
9
|
+
include ActiveModel::Validations::Callbacks
|
9
10
|
include ActiveModel::Conversion
|
10
11
|
|
11
12
|
extend ActiveModel::Naming
|
@@ -14,9 +15,13 @@ module MiniForm
|
|
14
15
|
extend ClassMethods
|
15
16
|
|
16
17
|
define_model_callbacks :update
|
18
|
+
define_model_callbacks :assigment
|
17
19
|
|
18
20
|
before_update :before_update
|
19
21
|
after_update :after_update
|
22
|
+
|
23
|
+
before_assigment :before_assigment
|
24
|
+
after_assigment :after_assigment
|
20
25
|
end
|
21
26
|
end
|
22
27
|
|
@@ -29,11 +34,15 @@ module MiniForm
|
|
29
34
|
end
|
30
35
|
|
31
36
|
def attributes=(attributes)
|
32
|
-
|
33
|
-
|
37
|
+
run_callbacks :assigment do
|
38
|
+
attributes.slice(*self.class.attribute_names).each do |name, value|
|
39
|
+
public_send "#{name}=", value
|
40
|
+
end
|
34
41
|
end
|
35
42
|
end
|
36
43
|
|
44
|
+
alias_method :assign_attributes, :attributes=
|
45
|
+
|
37
46
|
def attributes
|
38
47
|
Hash[self.class.attribute_names.map { |name| [name, public_send(name)] }]
|
39
48
|
end
|
@@ -54,7 +63,7 @@ module MiniForm
|
|
54
63
|
end
|
55
64
|
|
56
65
|
def update!(attributes = {})
|
57
|
-
fail InvalidForm unless update attributes
|
66
|
+
fail InvalidForm, self unless update attributes
|
58
67
|
self
|
59
68
|
end
|
60
69
|
|
@@ -85,8 +94,25 @@ module MiniForm
|
|
85
94
|
# noop
|
86
95
|
end
|
87
96
|
|
97
|
+
def before_assigment
|
98
|
+
# noop
|
99
|
+
end
|
100
|
+
|
101
|
+
def after_assigment
|
102
|
+
# noop
|
103
|
+
end
|
104
|
+
|
88
105
|
module ClassMethods
|
89
|
-
|
106
|
+
def inherited(base)
|
107
|
+
new_attribute_names = attribute_names.dup
|
108
|
+
new_models_to_save = models_to_save.dup
|
109
|
+
|
110
|
+
base.instance_eval do
|
111
|
+
@attribute_names = new_attribute_names
|
112
|
+
@models_to_save = new_models_to_save
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
90
116
|
def attribute_names
|
91
117
|
@attribute_names ||= []
|
92
118
|
end
|
@@ -102,15 +128,18 @@ module MiniForm
|
|
102
128
|
if delegate.nil?
|
103
129
|
attr_accessor(*attributes)
|
104
130
|
else
|
105
|
-
|
106
|
-
|
131
|
+
delegate(*attributes, to: delegate, prefix: prefix, allow_nil: allow_nil)
|
132
|
+
delegate(*attributes.map { |attr| "#{attr}=" }, to: delegate, prefix: prefix, allow_nil: allow_nil)
|
107
133
|
end
|
108
134
|
end
|
109
135
|
|
110
|
-
def model(name, attributes: [], prefix: nil, allow_nil: nil, save: false)
|
111
|
-
|
136
|
+
def model(name, attributes: [], read: [], prefix: nil, allow_nil: nil, save: false) # rubocop:disable ParameterLists
|
137
|
+
attr_accessor name
|
138
|
+
|
112
139
|
attributes(*attributes, delegate: name, prefix: prefix, allow_nil: allow_nil) unless attributes.empty?
|
113
140
|
|
141
|
+
delegate(*read, to: name, prefix: prefix, allow_nil: nil)
|
142
|
+
|
114
143
|
validates name, 'mini_form/nested' => true
|
115
144
|
|
116
145
|
models_to_save << name if save
|
data/lib/mini_form/version.rb
CHANGED
data/spec/mini_form_spec.rb
CHANGED
@@ -2,18 +2,19 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
module MiniForm
|
4
4
|
describe Model do
|
5
|
-
let(:user) { User.new name: '
|
5
|
+
let(:user) { User.new id: 1, name: 'name', age: 28 }
|
6
6
|
|
7
7
|
class User
|
8
8
|
include ActiveModel::Model
|
9
9
|
|
10
|
-
attr_accessor :name
|
10
|
+
attr_accessor :id, :name, :age
|
11
11
|
|
12
12
|
validates :name, presence: true
|
13
13
|
end
|
14
14
|
|
15
15
|
Example = Class.new do
|
16
16
|
include Model
|
17
|
+
|
17
18
|
attributes :name, :price
|
18
19
|
end
|
19
20
|
|
@@ -29,12 +30,6 @@ module MiniForm
|
|
29
30
|
end
|
30
31
|
end
|
31
32
|
|
32
|
-
ExampleWithModel = Class.new do
|
33
|
-
include Model
|
34
|
-
|
35
|
-
model :user, attributes: %i(name)
|
36
|
-
end
|
37
|
-
|
38
33
|
describe 'acts as ActiveModel' do
|
39
34
|
include ActiveModel::Lint::Tests
|
40
35
|
|
@@ -59,6 +54,23 @@ module MiniForm
|
|
59
54
|
end
|
60
55
|
end
|
61
56
|
|
57
|
+
describe 'inheritance' do
|
58
|
+
it 'can be inherited' do
|
59
|
+
parent_class = Class.new do
|
60
|
+
include Model
|
61
|
+
|
62
|
+
attributes :name
|
63
|
+
end
|
64
|
+
|
65
|
+
child_class = Class.new(parent_class) do
|
66
|
+
attributes :age
|
67
|
+
end
|
68
|
+
|
69
|
+
expect(parent_class.attribute_names).to eq %i(name)
|
70
|
+
expect(child_class.attribute_names).to eq %i(name age)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
62
74
|
describe '.attributes' do
|
63
75
|
it 'generates getters' do
|
64
76
|
object = Example.new name: 'value'
|
@@ -88,19 +100,36 @@ module MiniForm
|
|
88
100
|
end
|
89
101
|
|
90
102
|
describe '.model' do
|
103
|
+
ExampleWithModel = Class.new do
|
104
|
+
include Model
|
105
|
+
|
106
|
+
model :user, attributes: %i(name), read: %i(id)
|
107
|
+
|
108
|
+
def initialize(user)
|
109
|
+
self.user = user
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
91
113
|
it 'generates model accessors' do
|
92
|
-
object = ExampleWithModel.new user
|
114
|
+
object = ExampleWithModel.new user
|
93
115
|
expect(object.user).to eq user
|
94
116
|
end
|
95
117
|
|
118
|
+
it 'can delegate only a reader' do
|
119
|
+
object = ExampleWithModel.new user
|
120
|
+
|
121
|
+
expect(object).not_to respond_to :id=
|
122
|
+
expect(object.id).to eq user.id
|
123
|
+
end
|
124
|
+
|
96
125
|
it 'can delegate model attributes' do
|
97
|
-
object = ExampleWithModel.new user
|
126
|
+
object = ExampleWithModel.new user
|
98
127
|
expect(object.name).to eq user.name
|
99
128
|
end
|
100
129
|
|
101
130
|
it 'performs nested validation for model' do
|
102
131
|
user = User.new
|
103
|
-
object = ExampleWithModel.new user
|
132
|
+
object = ExampleWithModel.new user
|
104
133
|
|
105
134
|
expect(object).not_to be_valid
|
106
135
|
expect(object.errors[:name]).to be_present
|
@@ -143,6 +172,24 @@ module MiniForm
|
|
143
172
|
end
|
144
173
|
end
|
145
174
|
|
175
|
+
['attributes=', 'assign_attributes'].each do |method_name|
|
176
|
+
describe "##{method_name}" do
|
177
|
+
it 'sets attributes' do
|
178
|
+
object = Example.new
|
179
|
+
object.public_send method_name, name: 'iPhone', price: '$5'
|
180
|
+
|
181
|
+
expect(object.attributes).to eq name: 'iPhone', price: '$5'
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'ignores not listed attributes' do
|
185
|
+
object = Example.new
|
186
|
+
object.public_send method_name, invalid: 'value'
|
187
|
+
|
188
|
+
expect(object.attributes).to eq name: nil, price: nil
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
146
193
|
describe '#update' do
|
147
194
|
ExampleForUpdate = Class.new do
|
148
195
|
include Model
|
@@ -156,6 +203,10 @@ module MiniForm
|
|
156
203
|
include Model
|
157
204
|
|
158
205
|
model :user, attributes: %i(name), save: true
|
206
|
+
|
207
|
+
def initialize(user: user)
|
208
|
+
self.user = user
|
209
|
+
end
|
159
210
|
end
|
160
211
|
|
161
212
|
it 'updates attributes' do
|
@@ -197,6 +248,15 @@ module MiniForm
|
|
197
248
|
object.update
|
198
249
|
end
|
199
250
|
|
251
|
+
it 'supports assign callbacks' do
|
252
|
+
object = ExampleForUpdate.new
|
253
|
+
|
254
|
+
expect(object).to receive(:before_assigment)
|
255
|
+
expect(object).to receive(:after_assigment)
|
256
|
+
|
257
|
+
object.update name: 'value'
|
258
|
+
end
|
259
|
+
|
200
260
|
it 'returns false when validations fail' do
|
201
261
|
object = ExampleForUpdate.new name: nil
|
202
262
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mini_form
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Radoslav Stankov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-05-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|