reform 0.2.7 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.md +18 -0
- data/Gemfile +2 -1
- data/README.md +196 -17
- data/TODO.md +14 -3
- data/database.sqlite3 +0 -0
- data/lib/reform.rb +9 -1
- data/lib/reform/composition.rb +41 -34
- data/lib/reform/contract.rb +109 -0
- data/lib/reform/contract/errors.rb +33 -0
- data/lib/reform/contract/setup.rb +44 -0
- data/lib/reform/contract/validate.rb +48 -0
- data/lib/reform/form.rb +13 -309
- data/lib/reform/form/active_model.rb +8 -5
- data/lib/reform/form/active_record.rb +30 -37
- data/lib/reform/form/coercion.rb +10 -11
- data/lib/reform/form/composition.rb +40 -50
- data/lib/reform/form/multi_parameter_attributes.rb +6 -1
- data/lib/reform/form/save.rb +61 -0
- data/lib/reform/form/sync.rb +60 -0
- data/lib/reform/form/validate.rb +104 -0
- data/lib/reform/form/virtual_attributes.rb +3 -5
- data/lib/reform/representer.rb +17 -3
- data/lib/reform/version.rb +1 -1
- data/reform.gemspec +2 -1
- data/test/active_model_test.rb +0 -92
- data/test/as_test.rb +75 -0
- data/test/coercion_test.rb +26 -8
- data/test/composition_test.rb +8 -8
- data/test/contract_test.rb +57 -0
- data/test/errors_test.rb +37 -10
- data/test/feature_test.rb +28 -0
- data/test/form_builder_test.rb +105 -0
- data/test/form_composition_test.rb +30 -13
- data/test/nested_form_test.rb +12 -18
- data/test/reform_test.rb +11 -6
- data/test/save_test.rb +81 -0
- data/test/setup_test.rb +38 -0
- data/test/sync_test.rb +39 -0
- data/test/test_helper.rb +36 -2
- data/test/validate_test.rb +191 -0
- metadata +42 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 331784eaf17a8dc17f08c7c39cdb60af3bf502ed
|
4
|
+
data.tar.gz: 48cc28e685c889c3fd7ca7290215c5c4d1801ec1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 983557534185ed0d80afaccd6b433abb2ffe97fb5e44898bb915bb8d44b92f68d11447e2e30d7839be23c8f91cd374ffefe98a704eabe8f54763f13a09ade2dd
|
7
|
+
data.tar.gz: fbf1dc09a1197491e17fd4e36d137a98309fa05310f18e40804093ba6e1af3b08959f524293eef751fe5cbc0a21e73bd915d1a76fdddf4eb63091e203332342e
|
data/CHANGES.md
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
## 1.0.0
|
2
|
+
|
3
|
+
* Removed `Form::DSL` in favour of `Form::Composition`.
|
4
|
+
* Simplified nested forms. You can now do
|
5
|
+
```ruby
|
6
|
+
validates :songs, :length => {:minimum => 1}
|
7
|
+
validates :hit, :presence => true
|
8
|
+
```
|
9
|
+
* Allow passing symbol hash keys into `#validate`.
|
10
|
+
* Unlimited nesting of forms, if you really want that.
|
11
|
+
* `save` gets called on all nested forms automatically, disable with `save: false`.
|
12
|
+
* Renaming with `as:` now works everywhere.
|
13
|
+
* Fixes to make `Composition` work everywhere.
|
14
|
+
* Extract setup and validate into `Contract`.
|
15
|
+
* Automatic population with `:populate_if_empty` in `#validate`.
|
16
|
+
* Remove `#from_hash` and `#to_hash`.
|
17
|
+
* Introduce `#sync` and make `#save` less smart.
|
18
|
+
|
1
19
|
## 0.2.7
|
2
20
|
|
3
21
|
* Last release supporting Representable 1.7.
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -4,11 +4,6 @@ Decouple your models from forms. Reform gives you a form object with validations
|
|
4
4
|
|
5
5
|
Although reform can be used in any Ruby framework, it comes with [Rails support](#rails-integration), works with [simple_form and other form gems](#formbuilder-support), allows nesting forms to implement [has_one](#nesting-forms-1-1-relations) and [has_many](#nesting-forms-1-n-relations) relationships, can [compose a form](#compositions) from multiple objects and gives you [coercion](#coercion).
|
6
6
|
|
7
|
-
# Development Status
|
8
|
-
|
9
|
-
Dear Reform users - you know I love all of you. Reform is currently being improved by myself. I am definitely *not* resisting all of the feature requests (especially about nesting, model validations, automatic model setup when validating has_many, etc.) but working hard to make it better. Expect a new Reform version _and_ better README mid-late April and please refrain from telling me how lazy I am. Thanks and see you soon!!! :heart:
|
10
|
-
|
11
|
-
|
12
7
|
## Installation
|
13
8
|
|
14
9
|
Add this line to your Gemfile:
|
@@ -17,6 +12,14 @@ Add this line to your Gemfile:
|
|
17
12
|
gem 'reform'
|
18
13
|
```
|
19
14
|
|
15
|
+
## Nomenclatura
|
16
|
+
|
17
|
+
Reform comes with two base classes.
|
18
|
+
|
19
|
+
* `Form` is what made you come here - it gives you a form class to handle all validations, wrap models, allow rendering with Rails form helpers, simplifies saving of models, and more.
|
20
|
+
* `Contract` gives you a sub-set of `Form`: [this class](#contracts) is meant for API validation where already populated models get validated without having to maintain validations in the model classes.
|
21
|
+
|
22
|
+
|
20
23
|
## Defining Forms
|
21
24
|
|
22
25
|
You're working at a famous record label and your job is archiving all the songs, albums and artists. You start with a form to populate your `songs` table.
|
@@ -34,7 +37,20 @@ end
|
|
34
37
|
To add fields to the form use the `::property` method. Also, validations no longer go into the model but sit in the form.
|
35
38
|
|
36
39
|
|
37
|
-
##
|
40
|
+
## The API
|
41
|
+
|
42
|
+
Forms have a ridiculously simple API with only a handful of public methods.
|
43
|
+
|
44
|
+
1. `#initialize` always requires a model that the form represents.
|
45
|
+
2. `#validate(params)` will run all validations for the form with the input data. Its return value is the boolean result of the validations.
|
46
|
+
3. `#errors` returns validation messages in a classy ActiveModel style.
|
47
|
+
4. `#sync` writes form data back to the model. This will only use setter methods on the model(s).
|
48
|
+
5. `#save` (optional) will call `#save` on the model and nested models. Note that this implies a `#sync` call.
|
49
|
+
|
50
|
+
In addition to the main API, forms expose accessors to the defined properties. This is used for rendering or manual operations.
|
51
|
+
|
52
|
+
|
53
|
+
## Setup
|
38
54
|
|
39
55
|
In your controller you'd create a form instance and pass in the models you wanna work on.
|
40
56
|
|
@@ -54,6 +70,25 @@ class SongsController
|
|
54
70
|
end
|
55
71
|
```
|
56
72
|
|
73
|
+
Reform will read property values from the model in setup. Given the following form class.
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
class SongForm < Reform::Form
|
77
|
+
property :title
|
78
|
+
```
|
79
|
+
|
80
|
+
Internally, this form will call `song.title` to populate the title field.
|
81
|
+
|
82
|
+
If you, for whatever reasons, want to use a different public name, use `:as`.
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
class SongForm < Reform::Form
|
86
|
+
property :name, as: :title
|
87
|
+
```
|
88
|
+
|
89
|
+
This will still call `song.title` but expose the attribute as `name`.
|
90
|
+
|
91
|
+
|
57
92
|
## Rendering Forms
|
58
93
|
|
59
94
|
Your `@form` is now ready to be rendered, either do it yourself or use something like Rails' `#form_for`, `simple_form` or `formtastic`.
|
@@ -65,7 +100,10 @@ Your `@form` is now ready to be rendered, either do it yourself or use something
|
|
65
100
|
= f.input :title
|
66
101
|
```
|
67
102
|
|
68
|
-
|
103
|
+
Nested forms and collections can easily rendered with `fields_for`, etc. Just use Reform as if it would be an ActiveModel instance in the view layer.
|
104
|
+
|
105
|
+
|
106
|
+
## Validation
|
69
107
|
|
70
108
|
After a form submission, you wanna validate the input.
|
71
109
|
|
@@ -86,9 +124,32 @@ Note that Reform only updates values of the internal form attributes - the under
|
|
86
124
|
This allows rendering the form after `validate` with the data that has been submitted. However, don't get confused, the model's values are still the old, original values and are only changed after a `#save` or `#sync` operation.
|
87
125
|
|
88
126
|
|
127
|
+
## Syncing Back
|
128
|
+
|
129
|
+
After validation, you have two choices: either call `#save` and let Reform sort out the rest. Or call `#sync`, which will write all the properties back to the model. In a nested form, this works recursively, of course.
|
130
|
+
|
131
|
+
It's then up to you what to do with the updated models - they're still unsaved.
|
132
|
+
|
133
|
+
|
89
134
|
## Saving Forms
|
90
135
|
|
91
|
-
|
136
|
+
The easiest way to save the data is to call `#save` on the form.
|
137
|
+
|
138
|
+
```ruby
|
139
|
+
@form.save #=> populates song with incoming data
|
140
|
+
# by calling @form.song.title= and @form.song.length=.
|
141
|
+
```
|
142
|
+
|
143
|
+
This will sync the data to the model and then call `song.save`.
|
144
|
+
|
145
|
+
Sometimes, you need to do stuff manually.
|
146
|
+
|
147
|
+
|
148
|
+
## Saving Forms Manually
|
149
|
+
|
150
|
+
This is where you call `#save` with a block. This won't touch the models at all but give you a nice hash, so you can do it yourself.
|
151
|
+
|
152
|
+
Note that you can call `#sync` and _then_ call `#save` with the block to save models yourself.
|
92
153
|
|
93
154
|
```ruby
|
94
155
|
if @form.validate(params[:song])
|
@@ -97,7 +158,7 @@ We provide a bullet-proof way to save your form data: by letting _you_ do it!
|
|
97
158
|
data.title #=> "Rio"
|
98
159
|
data.length #=> "366"
|
99
160
|
|
100
|
-
nested #=> {title: "Rio"}
|
161
|
+
nested #=> {title: "Rio", length: "366"}
|
101
162
|
|
102
163
|
Song.create(nested)
|
103
164
|
end
|
@@ -105,17 +166,50 @@ We provide a bullet-proof way to save your form data: by letting _you_ do it!
|
|
105
166
|
|
106
167
|
While `data` gives you an object exposing the form property readers, `nested` is a hash reflecting the nesting structure of your form. Note how you can use arbitrary code to create/update models - in this example, we used `Song::create`.
|
107
168
|
|
108
|
-
|
169
|
+
|
170
|
+
## Contracts
|
171
|
+
|
172
|
+
Contracts give you a sub-set of the `Form` API.
|
173
|
+
|
174
|
+
1. `#initialize` accepts an already populated model.
|
175
|
+
2. `#validate` will run defined validations (without accepting a params hash as in `Form`).
|
176
|
+
|
177
|
+
Contracts can be used to completely remove validation logic from your model classes. Validation should happen in a separate layer - a `Contract`.
|
178
|
+
|
179
|
+
### Defining Contracts
|
180
|
+
|
181
|
+
A contract looks like a form.
|
109
182
|
|
110
183
|
```ruby
|
111
|
-
|
112
|
-
|
184
|
+
class AlbumContract < Reform::Contract
|
185
|
+
property :title
|
186
|
+
validates :title, length: {minimum: 9}
|
187
|
+
|
188
|
+
collection :songs do
|
189
|
+
property :title
|
190
|
+
validates :title, presence: true
|
191
|
+
end
|
113
192
|
```
|
114
193
|
|
115
|
-
|
194
|
+
It defines the validations and the object graph to be run.
|
195
|
+
|
196
|
+
In future versions and with the upcoming [Trailblazer framework](https://github.com/apotonick/trailblazer), contracts can be inherited from forms, representers, and cells, and vice-versa. Actually this already works with representer inheritance - let me know if you need help.
|
116
197
|
|
117
|
-
|
198
|
+
### Using Contracts
|
118
199
|
|
200
|
+
Applying a contract is simple, all you need is a populated object (e.g. an album after `#update_attributes`).
|
201
|
+
|
202
|
+
```ruby
|
203
|
+
album.update_attributes(..)
|
204
|
+
|
205
|
+
if AlbumContract.new(album).validate
|
206
|
+
album.save
|
207
|
+
else
|
208
|
+
raise album.errors.messages.inspect
|
209
|
+
end
|
210
|
+
```
|
211
|
+
|
212
|
+
Contracts help you to make your data layer a dumb persistance tier. My [upcoming book discusses that in detail](http://nicksda.apotomo.de).
|
119
213
|
|
120
214
|
|
121
215
|
## Nesting Forms: 1-1 Relations
|
@@ -201,6 +295,7 @@ Supposed you use reform's automatic save without a block, the following assignme
|
|
201
295
|
```ruby
|
202
296
|
form.song.title = "Hungry Like The Wolf"
|
203
297
|
form.song.artist.name = "Duran Duran"
|
298
|
+
form.song.save
|
204
299
|
```
|
205
300
|
|
206
301
|
## Nesting Forms: 1-n Relations
|
@@ -266,6 +361,69 @@ end
|
|
266
361
|
```
|
267
362
|
|
268
363
|
|
364
|
+
## Nesting Configuration
|
365
|
+
|
366
|
+
### Turning Off Autosave
|
367
|
+
|
368
|
+
You can assign Reform to _not_ call `save` on a particular nested model (per default, it is called automatically on all nested models).
|
369
|
+
|
370
|
+
```ruby
|
371
|
+
class AlbumForm < Reform::Form
|
372
|
+
# ...
|
373
|
+
|
374
|
+
collection :songs, save: false do
|
375
|
+
# ..
|
376
|
+
end
|
377
|
+
```
|
378
|
+
|
379
|
+
The `:save` options set to false won't save models.
|
380
|
+
|
381
|
+
|
382
|
+
### Populating Forms For Validation
|
383
|
+
|
384
|
+
With a complex nested setup it can sometimes be painful to setup the model object graph.
|
385
|
+
|
386
|
+
Let's assume you rendered the following form.
|
387
|
+
|
388
|
+
```ruby
|
389
|
+
@form = AlbumForm.new(Album.new(songs: [Song.new, Song.new]))
|
390
|
+
```
|
391
|
+
|
392
|
+
This will render two nested forms to create new songs.
|
393
|
+
|
394
|
+
When **validating**, you're supposed to setup the very same object graph, again. Reform has no way of remembering what the object setup was like a request ago.
|
395
|
+
|
396
|
+
So, the following code will fail.
|
397
|
+
|
398
|
+
```ruby
|
399
|
+
@form = AlbumForm.new(Album.new).validate(params[:album])
|
400
|
+
```
|
401
|
+
|
402
|
+
However, you can advise Reform to setup the correct objects for you.
|
403
|
+
|
404
|
+
```ruby
|
405
|
+
class AlbumForm < Reform::Form
|
406
|
+
# ...
|
407
|
+
|
408
|
+
collection :songs, populate_if_empty: Song do
|
409
|
+
# ..
|
410
|
+
end
|
411
|
+
```
|
412
|
+
|
413
|
+
This works for both `property` and `collection` and instantiates `Song` objects where they're missing when calling `#validate`.
|
414
|
+
|
415
|
+
If you wanna create the objects yourself, because you're smarter than Reform, do it with a lambda.
|
416
|
+
|
417
|
+
```ruby
|
418
|
+
class AlbumForm < Reform::Form
|
419
|
+
# ...
|
420
|
+
|
421
|
+
collection :songs, populate_if_empty: lambda { |fragment, args| Song.new } do
|
422
|
+
# ..
|
423
|
+
end
|
424
|
+
```
|
425
|
+
|
426
|
+
|
269
427
|
## Compositions
|
270
428
|
|
271
429
|
Sometimes you might want to embrace two (or more) unrelated objects with a single form. While you could write a simple delegating composition yourself, reform comes with it built-in.
|
@@ -405,7 +563,9 @@ Reform doesn't really know whether it's working with a PORO, an `ActiveRecord` i
|
|
405
563
|
|
406
564
|
When rendering the form, reform calls readers on the decorated model to retrieve the field data (`Song#title`, `Song#length`).
|
407
565
|
|
408
|
-
When
|
566
|
+
When syncing a submitted form, the same happens using writers. Reform simply calls `Song#title=(value)`. No knowledge is required about the underlying database layer.
|
567
|
+
|
568
|
+
The same applies to saving: Reform will call `#save` on the main model and nested models.
|
409
569
|
|
410
570
|
Nesting forms only requires readers for the nested properties as `Album#songs`.
|
411
571
|
|
@@ -426,7 +586,6 @@ However, you should know about two things.
|
|
426
586
|
Reform provides the following `ActiveRecord` specific features. They're mixed in automatically in a Rails/AR setup.
|
427
587
|
|
428
588
|
* Uniqueness validations. Use `validates_uniqueness_of` in your form.
|
429
|
-
* Calling `Form#save` will explicitely call `save` on your model (added in 0.2.1) which will usually trigger a database insertion or update.
|
430
589
|
|
431
590
|
As mentioned in the [Rails Integration](https://github.com/apotonick/reform#rails-integration) section some Rails 4 setups do not properly load.
|
432
591
|
|
@@ -518,6 +677,26 @@ class SongForm < Reform::Form
|
|
518
677
|
|
519
678
|
This will capitalize the title _after_ calling `form.validate` but _before_ validation happens. Note that you can use `super` to call the original setter.
|
520
679
|
|
680
|
+
|
681
|
+
## Undocumented Features
|
682
|
+
|
683
|
+
_(Please don't read this section!)_
|
684
|
+
|
685
|
+
|
686
|
+
### Populator
|
687
|
+
|
688
|
+
You can run your very own populator logic if you're keen (and you know what you're doing).
|
689
|
+
|
690
|
+
```ruby
|
691
|
+
class AlbumForm < Reform::Form
|
692
|
+
# ...
|
693
|
+
|
694
|
+
collection :songs, populator: lambda { |fragment, args| args.binding[:form].new(Song.find fragment[:id]) } do
|
695
|
+
# ..
|
696
|
+
end
|
697
|
+
```
|
698
|
+
|
699
|
+
|
521
700
|
## Support
|
522
701
|
|
523
702
|
If you run into any trouble chat with us on irc.freenode.org#trailblazer.
|
@@ -532,4 +711,4 @@ If you run into any trouble chat with us on irc.freenode.org#trailblazer.
|
|
532
711
|
|
533
712
|
### Attributions!!!
|
534
713
|
|
535
|
-
Great thanks to [Blake Education](https://github.com/blake-education) for giving us the freedom and time to develop this project while working on their project.
|
714
|
+
Great thanks to [Blake Education](https://github.com/blake-education) for giving us the freedom and time to develop this project in 2013 while working on their project.
|
data/TODO.md
CHANGED
@@ -4,11 +4,22 @@
|
|
4
4
|
* document Form#to_hash and Form#to_nested_hash (e.g. with OpenStruct composition to make it a very simple form)
|
5
5
|
* document getter: and representer_exec:
|
6
6
|
|
7
|
-
*
|
8
|
-
*
|
7
|
+
* Debug module that logs every step.
|
8
|
+
* no setters in Contract#setup
|
9
9
|
|
10
10
|
vererben in inline representern (module zum einmixen, attrs löschen)
|
11
11
|
|
12
12
|
# TODO: remove the concept of Errors#messages and just iterate over Errors.
|
13
13
|
# each form contains its local field errors in Errors
|
14
|
-
# form.messages should then go through them and compile a "summary" instead of adding them to the parents #errors in #validate.
|
14
|
+
# form.messages should then go through them and compile a "summary" instead of adding them to the parents #errors in #validate.
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
in a perfect world, a UI form would send JSON as in the API. that's why the reform form creates the correct object graph first, then validates. creating the graph usually happens in the API representer code.
|
19
|
+
|
20
|
+
|
21
|
+
WHY DON'T PEOPLE USE THIS:
|
22
|
+
http://guides.rubyonrails.org/association_basics.html#the-has-many-association
|
23
|
+
4.2.2.2 :autosave
|
24
|
+
|
25
|
+
If you set the :autosave option to true, Rails will save any loaded members and destroy members that are marked for destruction whenever you save the parent object.
|
data/database.sqlite3
CHANGED
Binary file
|
data/lib/reform.rb
CHANGED
@@ -1,7 +1,15 @@
|
|
1
|
+
module Reform
|
2
|
+
autoload :Contract, 'reform/contract'
|
3
|
+
|
4
|
+
def self.rails3_0?
|
5
|
+
::ActiveModel::VERSION::MAJOR == 3 and ::ActiveModel::VERSION::MINOR == 0
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
1
9
|
require 'reform/form'
|
2
10
|
require 'reform/form/composition'
|
3
11
|
require 'reform/form/active_model'
|
4
12
|
|
5
13
|
if defined?(Rails) # DISCUSS: is everyone ok with this?
|
6
14
|
require 'reform/rails'
|
7
|
-
end
|
15
|
+
end
|
data/lib/reform/composition.rb
CHANGED
@@ -1,54 +1,61 @@
|
|
1
|
+
require 'disposable/composition'
|
2
|
+
|
1
3
|
module Reform
|
2
|
-
|
3
|
-
|
4
|
-
class << self
|
5
|
-
def map(options)
|
6
|
-
@attr2obj = {} # {song: ["title", "track"], artist: ["name"]}
|
4
|
+
class Expose
|
5
|
+
include Disposable::Composition
|
7
6
|
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
# DISCUSS: this might be moved to Disposable::Twin::Expose.
|
8
|
+
class << self
|
9
|
+
# Builder for a concrete Composition class with configurations from the form's representer.
|
10
|
+
def from(representer)
|
11
|
+
options = {}
|
11
12
|
|
12
|
-
|
13
|
+
representer.representable_attrs.each do |definition|
|
14
|
+
process_definition!(options, definition)
|
13
15
|
end
|
14
|
-
end
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
representer.representable_attrs.each do |cfg|
|
20
|
-
options[cfg.options[:on]] ||= []
|
21
|
-
options[cfg.options[:on]] << cfg.name
|
17
|
+
Class.new(self).tap do |composition| # for 1.8 compat. you're welcome.
|
18
|
+
composition.map(options)
|
19
|
+
# puts composition@map.inspect
|
22
20
|
end
|
23
|
-
|
24
|
-
map options
|
25
21
|
end
|
26
22
|
|
27
|
-
|
28
|
-
|
23
|
+
private
|
24
|
+
def process_definition!(options, definition)
|
25
|
+
options[:model] ||= []
|
26
|
+
options[:model] << [definition[:private_name], definition.name].compact
|
29
27
|
end
|
28
|
+
end
|
29
|
+
end
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
31
|
+
# Keeps composition of models and knows how to transform a plain hash into a nested hash.
|
32
|
+
class Composition < Expose
|
33
|
+
|
34
|
+
# DISCUSS: this might be moved to Disposable::Twin::Composition.
|
35
|
+
class << self
|
36
|
+
# Builder for a concrete Composition class with configurations from the form's representer.
|
37
|
+
def process_definition!(options, definition)
|
38
|
+
options[definition[:on]] ||= []
|
39
|
+
options[definition[:on]] << [definition[:private_name], definition.name].compact
|
35
40
|
end
|
36
41
|
end
|
37
42
|
|
38
|
-
|
43
|
+
def save
|
44
|
+
each { |model| model.save }
|
45
|
+
end
|
46
|
+
|
39
47
|
def nested_hash_for(attrs)
|
40
48
|
{}.tap do |hsh|
|
41
49
|
attrs.each do |name, val|
|
42
|
-
obj = self.class.model_for_property(name)
|
43
|
-
|
44
|
-
hsh[obj][name.to_sym] = val
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
50
|
+
#obj = self.class.model_for_property(name)
|
51
|
+
config = self.class.instance_variable_get(:@map)[name.to_sym]
|
48
52
|
|
49
|
-
|
50
|
-
|
51
|
-
|
53
|
+
model = config[:model]
|
54
|
+
method = config[:method]
|
55
|
+
|
56
|
+
hsh[model] ||= {}
|
57
|
+
hsh[model][method] = val
|
58
|
+
end
|
52
59
|
end
|
53
60
|
end
|
54
61
|
end
|