restfulie 0.1 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +305 -26
- data/Rakefile +1 -1
- data/lib/restfulie.rb +88 -18
- metadata +2 -2
data/README.textile
CHANGED
@@ -1,13 +1,21 @@
|
|
1
1
|
h1. Quit pretending
|
2
2
|
|
3
|
-
CRUD through HTTP is a good step forward to using resources and becoming
|
3
|
+
CRUD through HTTP is a good step forward to using resources and becoming RESTful, another step further into it is to make use of hypermedia based services and this gem allows you to do it really fast.
|
4
|
+
|
5
|
+
h2. Why would I use restfulie?
|
6
|
+
|
7
|
+
1. Easy --> writing hypermedia aware resource based clients
|
8
|
+
2. Easy --> hypermedia aware resource based services
|
9
|
+
3. Small -> it's not a bloated solution with a huge list of APIs
|
10
|
+
4. HATEOAS --> clients you are unaware of will not bother if you change your URIs
|
11
|
+
5. HATEOAS --> services that you consume will not affect your software whenever they change part of their flow or URIs
|
4
12
|
|
5
13
|
h1. Restfulie: client-side
|
6
14
|
|
7
|
-
|
15
|
+
Example on accessing a resource and its services through the restfulie API:
|
8
16
|
|
9
17
|
<pre>
|
10
|
-
order = Order.from_web resource_uri
|
18
|
+
order = Order.from_web resource_uri
|
11
19
|
|
12
20
|
puts "Order price is #{order.price}"
|
13
21
|
|
@@ -21,14 +29,59 @@ h1. Restfulie: server-side
|
|
21
29
|
This is a simple example how to make your state changes available to your resource consumers:
|
22
30
|
|
23
31
|
<pre>
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
+
class Order < ActiveRecord::Base
|
33
|
+
def following_transitions
|
34
|
+
transitions = []
|
35
|
+
transitions << [:show, {}]
|
36
|
+
transitions << [:destroy, {}] if can_cancel?
|
37
|
+
transitions << [:pay, {:id => id}] if can_pay?
|
38
|
+
transitions << [:show, {:controller => :payments, :payment_id => payment.id }] if paid?
|
39
|
+
transitions
|
40
|
+
end
|
41
|
+
end
|
42
|
+
</pre>
|
43
|
+
|
44
|
+
*Do not forget to create a migration with a string field named status for your resource:*
|
45
|
+
|
46
|
+
<pre>
|
47
|
+
scripts/generate migration add_status_to_order
|
48
|
+
</pre>
|
49
|
+
|
50
|
+
Content:
|
51
|
+
|
52
|
+
<pre>
|
53
|
+
class AddStatusToOrder < ActiveRecord::Migration
|
54
|
+
def self.up
|
55
|
+
add_column :orders, :status, :string
|
56
|
+
Order.all.each do |order|
|
57
|
+
order.status = "unpaid"
|
58
|
+
order.save
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.down
|
63
|
+
remove_column :orders, :status
|
64
|
+
end
|
65
|
+
end
|
66
|
+
</pre>
|
67
|
+
|
68
|
+
Or simply define a status reader and writer on your own.
|
69
|
+
|
70
|
+
|
71
|
+
|
72
|
+
h2. Restfulie server-side: state machine
|
73
|
+
|
74
|
+
For those willing to implement a more complex or advanced state machine, you can use the dsl-like api:
|
75
|
+
|
76
|
+
<pre>
|
77
|
+
class Order < ActiveRecord::Base
|
78
|
+
state :unpaid, :allow => [:latest, :pay, :cancel]
|
79
|
+
state :cancelled, :allow => :latest
|
80
|
+
|
81
|
+
transition :latest, {:action => :show}
|
82
|
+
transition :cancel, {:action => :destroy}, :cancelled
|
83
|
+
transition :pay, {}, :preparing
|
84
|
+
end
|
32
85
|
</pre>
|
33
86
|
|
34
87
|
h2. Installing
|
@@ -39,33 +92,35 @@ Just add in your environment.rb the following line:
|
|
39
92
|
config.gem "restfulie", :source => "http://gemcutter.org"
|
40
93
|
</pre>
|
41
94
|
|
42
|
-
|
95
|
+
And then execute:
|
43
96
|
<pre>rake gems:install</pre>
|
44
97
|
|
45
|
-
or, if you prefer to install as a plugin:
|
98
|
+
or, if you prefer to install it as a plugin:
|
46
99
|
|
47
|
-
script/plugin install git://github.com/caelum/restfulie.git
|
100
|
+
<pre>script/plugin install git://github.com/caelum/restfulie.git</pre>
|
48
101
|
|
49
|
-
h2. Typical
|
102
|
+
h2. Typical hypermedia aware example
|
50
103
|
|
51
|
-
Trying to follow the definition of a
|
104
|
+
Trying to follow the definition of a RESTful application supporting resources with hypermedia content, a resource would be:
|
52
105
|
|
53
106
|
<pre>
|
54
107
|
<order>
|
55
108
|
<product>basic rails course</product>
|
56
|
-
<product>
|
109
|
+
<product>RESTful training</product>
|
57
110
|
<atom:link rel="refresh" href="http://www.caelum.com.br/orders/1" xmlns:atom="http://www.w3.org/2005/Atom"/>
|
58
111
|
<atom:link rel="update" href="http://www.caelum.com.br/orders/1" xmlns:atom="http://www.w3.org/2005/Atom"/>
|
59
|
-
<atom:link rel="pay" href="http://www.caelum.com.br/orders/1" xmlns:atom="http://www.w3.org/2005/Atom"/>
|
112
|
+
<atom:link rel="pay" href="http://www.caelum.com.br/orders/1/pay" xmlns:atom="http://www.w3.org/2005/Atom"/>
|
60
113
|
<atom:link rel="destroy" href="http://www.caelum.com.br/orders/1" xmlns:atom="http://www.w3.org/2005/Atom"/>
|
61
114
|
</order>
|
62
115
|
</pre>
|
63
116
|
|
64
117
|
h2. Client Usage
|
65
118
|
|
66
|
-
One should first acquire the representation from the server through your common GET
|
119
|
+
One should first acquire the representation from the server through your common GET request and process it through the usual from_* methods:
|
67
120
|
<pre>xml = Net::HTTP.get(URI.parse('http://www.caelum.com.br/orders/1'))
|
68
121
|
order = Order.from_xml(xml)</pre>
|
122
|
+
or use the restfulie *from_web*:
|
123
|
+
<pre>order = Order.from_web 'http://www.caelum.com.br/orders/1'</pre>
|
69
124
|
|
70
125
|
And now you can invoke all those actions in order to change your resource's state:
|
71
126
|
|
@@ -73,7 +128,7 @@ And now you can invoke all those actions in order to change your resource's stat
|
|
73
128
|
order.refresh
|
74
129
|
order.update
|
75
130
|
order.destroy
|
76
|
-
order.pay
|
131
|
+
order.pay
|
77
132
|
</pre>
|
78
133
|
|
79
134
|
Note that:
|
@@ -84,28 +139,252 @@ Note that:
|
|
84
139
|
|
85
140
|
h2. Resource format support
|
86
141
|
|
87
|
-
Restfulie currently supports xml+atom and will soon expand its support to
|
142
|
+
Restfulie currently supports full xml+atom, partial xml+rel and will soon expand its support to json+links.
|
88
143
|
|
89
144
|
|
90
145
|
h2. Help
|
91
146
|
|
92
|
-
If you are looking for or want to help, let us know at the mailing list:
|
147
|
+
If you are looking for or want to help, let us know at the mailing list:
|
148
|
+
|
149
|
+
"http://groups.google.com/group/restfulie":http://groups.google.com/group/restfulie
|
150
|
+
|
151
|
+
h2. Client-side configuration: how to customize your request
|
93
152
|
|
94
|
-
|
153
|
+
h3. HTTP verbs
|
95
154
|
|
96
155
|
By default, restfulie uses the following table:
|
97
156
|
|
98
157
|
* destroy, cancel and delete send a DELETE request
|
99
|
-
* update sends a
|
100
|
-
* refresh, reload, show sends a GET request
|
158
|
+
* update sends a PUT request
|
159
|
+
* refresh, reload, show, latest sends a GET request
|
101
160
|
* other methods sends a POST request
|
102
161
|
|
103
162
|
If you want to use a custom http verb in order to send your request, you can do it by setting the optional string 'method':
|
104
163
|
|
164
|
+
<pre>order.update(:method=>"post")</pre>
|
165
|
+
|
166
|
+
h3. Request parameters
|
167
|
+
|
168
|
+
If you want to send extra parameters, you can do it through the *data* parameter:
|
169
|
+
|
170
|
+
<pre>order.pay(:data => {:payment => my_payment})</pre>
|
171
|
+
|
172
|
+
The parameters will be serialized either to xml or json according to which format was used to deserialize the order at first place.
|
173
|
+
|
174
|
+
h3. Executing another GET request
|
175
|
+
|
176
|
+
If your method executes another GET request, it will automatically deserialize its result as:
|
177
|
+
|
178
|
+
<pre>order = Order.from_web order_uri
|
179
|
+
payment = order.check_payment_info</pre>
|
180
|
+
|
181
|
+
If you want to parse the response yourself, instead of receiving just the final deserialized object, you can do it by passing a body to your method
|
182
|
+
|
183
|
+
<pre>order = Order.from_web order_uri
|
184
|
+
successful = order.check_payment_info do |response|
|
185
|
+
return response.code==200
|
186
|
+
end</pre>
|
187
|
+
|
188
|
+
h2. Server-side configuration
|
189
|
+
|
190
|
+
There are two different approaches that can be combined to create a full hypermedia aware resource based service, including awareness of its states and transitions.
|
191
|
+
|
192
|
+
h3. The following available transitions method
|
193
|
+
|
194
|
+
The most easy way to use restfulie is to write the *following_transitions* method.
|
195
|
+
It should return a list of possible transitions, where each transition is identified by an array of its name and definition.
|
196
|
+
|
197
|
+
The next example shows how to define a transition which will map to the current controller, action show:
|
198
|
+
|
199
|
+
<pre>
|
200
|
+
def following_transitions
|
201
|
+
transitions = []
|
202
|
+
transitions << [:show, {}]
|
203
|
+
transitions
|
204
|
+
end
|
205
|
+
</pre>
|
206
|
+
|
207
|
+
Which will generate an hyperlink as
|
208
|
+
|
209
|
+
<pre><atom:link rel="show" rel="http://yourserver/orders/15" /></pre>
|
210
|
+
|
211
|
+
h3. Customizing the rel name
|
212
|
+
|
213
|
+
You can also override the action used, but still keep the rel
|
214
|
+
|
105
215
|
<pre>
|
106
|
-
|
216
|
+
def following_transitions
|
217
|
+
transitions = []
|
218
|
+
transitions << [:cancel, { :action => :destroy }]
|
219
|
+
transitions
|
220
|
+
end
|
107
221
|
</pre>
|
108
222
|
|
223
|
+
Which will generate an hyperlink as
|
224
|
+
|
225
|
+
<pre><atom:link rel="cancel" rel="http://yourserver/orders/15" /></pre>
|
226
|
+
|
227
|
+
h3. Example
|
228
|
+
|
229
|
+
A full example showing all capabilities of this method follows:
|
230
|
+
|
231
|
+
<pre>
|
232
|
+
def following_transitions
|
233
|
+
transitions = []
|
234
|
+
transitions << [:show, {}]
|
235
|
+
transitions << [:destroy, {}] if can_cancel?
|
236
|
+
transitions << [:pay, {:id => id}] if can_pay?
|
237
|
+
transitions << [:show, {:controller => :payments, :payment_id => payment.id }] if paid?
|
238
|
+
transitions
|
239
|
+
end
|
240
|
+
</pre>
|
241
|
+
|
242
|
+
h2. Defining the state machine and its transitions
|
243
|
+
|
244
|
+
The second way of defining your available transitions is to explicitely define the states and transitions.
|
245
|
+
|
246
|
+
By using this approach, one has to define a new column named *status* in a database migration file.
|
247
|
+
|
248
|
+
The first step involves defining all your states, each one with its own name and possible transitions, as:
|
249
|
+
|
250
|
+
<pre>
|
251
|
+
state :state_name, :allow => [ :first_transition_name, :second_transition_name]
|
252
|
+
</pre>
|
253
|
+
|
254
|
+
The following example shows all possible states for an order:
|
255
|
+
|
256
|
+
<pre>
|
257
|
+
class Order < ActiveRecord::Base
|
258
|
+
state :unpaid, :allow => [:latest, :pay, :cancel]
|
259
|
+
state :cancelled, :allow => :latest
|
260
|
+
state :received, :allow => [:latest, :check_payment_info]
|
261
|
+
state :preparing, :allow => [:latest, :check_payment_info]
|
262
|
+
state :ready, :allow => [:latest, :receive, :check_payment_info]
|
263
|
+
end
|
264
|
+
</pre>
|
265
|
+
|
266
|
+
Now its time to define which controller and action each transition invokes, in a much similar way to
|
267
|
+
the transition definitions in the following_transitions method:
|
268
|
+
|
269
|
+
<pre>
|
270
|
+
class Order < ActiveRecord::Base
|
271
|
+
end
|
272
|
+
</pre>
|
273
|
+
|
274
|
+
Once a transition has been given a name, its name can be used in the following_transitions method also.
|
275
|
+
The next example does not configure the transition because it was already defined, only adding it to the
|
276
|
+
list of available transition whenever the *can_pay?* method returns true:
|
277
|
+
|
278
|
+
<pre>
|
279
|
+
class Order < ActiveRecord::Base
|
280
|
+
transition :pay, {:action => pay_this_order, :controller => :payments}, :preparing
|
281
|
+
|
282
|
+
def following_transitions
|
283
|
+
transitions = []
|
284
|
+
transitions << :pay if can_pay?
|
285
|
+
transitions
|
286
|
+
end
|
287
|
+
end
|
288
|
+
</pre>
|
289
|
+
|
290
|
+
Note that whenever one defines a transition, there is a third - optional - argument, this is the
|
291
|
+
transition's target's state. Whenever the method *order.pay* method is invoked in the *server*, it will
|
292
|
+
automatically change the order's status to *preparing*.
|
293
|
+
|
294
|
+
You can download the server side example to see the complete code.
|
295
|
+
|
296
|
+
The last usage of the transition definition involves passing a block which receives the element in which
|
297
|
+
the transition URI's is required. The block should return all the necessary information for retrieving the URI, now having access to your element's instance variables:
|
298
|
+
|
299
|
+
<pre>
|
300
|
+
class Order < ActiveRecord::Base
|
301
|
+
transition :check_payment_info do |order|
|
302
|
+
{:controller => :payments, :action => :show, :order_id => order.id, :payment_id => order.payments[0].id, :rel => "check_payment_info"}
|
303
|
+
end
|
304
|
+
end
|
305
|
+
</pre>
|
306
|
+
|
307
|
+
h3. Using xml+rel links instead of atom links
|
308
|
+
|
309
|
+
Atom is everywhere and can be consumed by a number of existing tools but if your system wants to supply its
|
310
|
+
services through commons rel+link xml as
|
311
|
+
|
312
|
+
<pre>
|
313
|
+
<order>
|
314
|
+
<product>basic rails course</product>
|
315
|
+
<product>RESTful training</product>
|
316
|
+
<refresh>http://www.caelum.com.br/orders/1</refresh>
|
317
|
+
<update>http://www.caelum.com.br/orders/1</update>
|
318
|
+
<pay>http://www.caelum.com.br/orders/1/pay</pay>
|
319
|
+
<destroy>http://www.caelum.com.br/orders/1</destroy>
|
320
|
+
</order>
|
321
|
+
</pre>
|
322
|
+
|
323
|
+
You can do it by passing the *use_name_based_link* argument:
|
324
|
+
|
325
|
+
<pre>
|
326
|
+
order.to_xml(:controller => my_controller, :use_name_based_link => true)
|
327
|
+
</pre>
|
328
|
+
|
329
|
+
h2. Team
|
330
|
+
|
331
|
+
Restfulie was created and is maintained within Caelum by
|
332
|
+
|
333
|
+
Projetct Founder
|
334
|
+
* "Guilherme Silveira":mailto:guilherme.silveira@caelum.com.br
|
335
|
+
|
336
|
+
Active Commiters
|
337
|
+
* "Caue Guerra":mailto:caue.guerra@gmail.com
|
338
|
+
* "Guilherme Silveira":mailto:guilherme.silveira@caelum.com.br
|
339
|
+
|
340
|
+
Contributors
|
341
|
+
* Diego Carrion
|
342
|
+
* Leandro Silva
|
343
|
+
* Gavin-John Noonan
|
344
|
+
|
345
|
+
h2. Try it online
|
346
|
+
|
347
|
+
We have a live example of a server implementation using a resource+hypermedia course ordering system available.
|
348
|
+
|
349
|
+
Follow the steps below to try out the system:
|
350
|
+
|
351
|
+
* "Access the server system":http://restfulie-test.heroku.com
|
352
|
+
* Create a couple of trainings
|
353
|
+
* Create an order
|
354
|
+
* Access the order listing and retrieve its xml link
|
355
|
+
|
356
|
+
And now you can try the restfulie client api through a simple and generic resource+hypermedia client application:
|
357
|
+
|
358
|
+
* "Access the client system":http://restfulie-client.heroku.com
|
359
|
+
* Enter your order uri
|
360
|
+
* Check your order information which was retrieved and all available actions
|
361
|
+
|
362
|
+
Now you can either:
|
363
|
+
|
364
|
+
* *latest* - refresh your order information _order.latest_
|
365
|
+
* *cancel* - cancel your order (dead end!) _order.destroy_
|
366
|
+
* *pay* - pay for your order, and don't forget to send your (fake) credit card information _order.pay(payment)_
|
367
|
+
* *check_payment_info* - after paying you can check the payment information stored at the server _order.check_payment_info_
|
368
|
+
|
369
|
+
In order to pay do not forget to send the parameter *payment* with a value as
|
370
|
+
|
371
|
+
<pre>
|
372
|
+
<payment>
|
373
|
+
<amount>15</amount>
|
374
|
+
<cardholder_name>Guilherme Silveira</cardholder_name>
|
375
|
+
<card_number>123456789012</card_number>
|
376
|
+
<expiry_month>12</expiry_month>
|
377
|
+
<expiry_year>12</expiry_year>
|
378
|
+
</payment>
|
379
|
+
</pre>
|
380
|
+
|
381
|
+
|
382
|
+
h3. Sources
|
383
|
+
|
384
|
+
"Client":http://github.com/caelum/restfulie-client
|
385
|
+
"Server":http://github.com/caelum/restfulie-test
|
386
|
+
|
387
|
+
|
109
388
|
h2. License
|
110
389
|
|
111
390
|
/***
|
data/Rakefile
CHANGED
@@ -5,7 +5,7 @@ require 'rake/gempackagetask'
|
|
5
5
|
require 'spec/rake/spectask'
|
6
6
|
|
7
7
|
GEM = "restfulie"
|
8
|
-
GEM_VERSION = "0.
|
8
|
+
GEM_VERSION = "0.2"
|
9
9
|
SUMMARY = "This is a small cute plugin to show how to implement hypermedia based services in a easy way using rails."
|
10
10
|
AUTHOR = "Guilherme Silveira, Caue Guerra"
|
11
11
|
EMAIL = "guilherme.silveira@caelum.com.br"
|
data/lib/restfulie.rb
CHANGED
@@ -5,28 +5,51 @@ module Restfulie
|
|
5
5
|
def to_json
|
6
6
|
super :methods => :following_states
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
def to_xml(options = {})
|
10
|
+
return super unless respond_to?(:status)
|
11
|
+
|
10
12
|
controller = options[:controller]
|
11
13
|
return super if controller.nil?
|
12
|
-
|
14
|
+
|
13
15
|
options[:skip_types] = true
|
14
16
|
super options do |xml|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
17
|
+
possible_following = []
|
18
|
+
default_transitions_map = self.class._transitions_for(status.to_sym)
|
19
|
+
default_transitions = default_transitions_map[:allow] unless default_transitions_map.nil?
|
20
|
+
|
21
|
+
possible_following += default_transitions unless default_transitions.nil?
|
22
|
+
possible_following += self.following_transitions if self.respond_to?(:following_transitions)
|
23
|
+
|
24
|
+
return super if possible_following.empty?
|
25
|
+
|
26
|
+
possible_following.each do |possible|
|
27
|
+
if possible.class.name=="Array"
|
28
|
+
name = possible[0]
|
29
|
+
result = [possible[1], nil]
|
30
|
+
else
|
31
|
+
name = possible
|
32
|
+
result = self.class._transitions(name.to_sym)
|
33
|
+
end
|
34
|
+
|
35
|
+
if result[0]
|
36
|
+
action = result[0]
|
37
|
+
body = result[1]
|
38
|
+
action = body.call(self) if body
|
39
|
+
|
40
|
+
rel = action[:rel] || name || action[:action]
|
41
|
+
action[:rel] = nil
|
42
|
+
else
|
43
|
+
action = {}
|
44
|
+
rel = name
|
45
|
+
end
|
46
|
+
|
47
|
+
action[:action] ||= name
|
48
|
+
translate_href = controller.url_for(action)
|
49
|
+
if options[:use_name_based_link]
|
50
|
+
xml.tag!(rel, translate_href)
|
51
|
+
else
|
52
|
+
xml.tag!('atom:link', 'xmlns:atom' => 'http://www.w3.org/2005/Atom', :rel => rel, :href => translate_href)
|
30
53
|
end
|
31
54
|
end
|
32
55
|
end
|
@@ -35,7 +58,14 @@ module Restfulie
|
|
35
58
|
def create_method(name, &block)
|
36
59
|
self.class.send(:define_method, name, &block)
|
37
60
|
end
|
38
|
-
|
61
|
+
|
62
|
+
def move_to(name)
|
63
|
+
transitions = self.class._transitions_for(self.status.to_sym)[:allow]
|
64
|
+
raise "Current state #{status} is invalid in order to execute #{name}. It must be one of #{transitions}" unless transitions.include? name
|
65
|
+
result = self.class._transitions(name)[2]
|
66
|
+
self.status = result.to_s unless result.nil?
|
67
|
+
end
|
68
|
+
|
39
69
|
end
|
40
70
|
|
41
71
|
module ActiveRecord
|
@@ -44,6 +74,45 @@ module ActiveRecord
|
|
44
74
|
include Restfulie
|
45
75
|
attr_accessor :_possible_states
|
46
76
|
attr_accessor :_came_from
|
77
|
+
|
78
|
+
def self._transitions_for(state)
|
79
|
+
@@states[state]
|
80
|
+
end
|
81
|
+
|
82
|
+
def self._transitions(name)
|
83
|
+
[@@transitions[name], @@bodies[name], @@results[name]]
|
84
|
+
end
|
85
|
+
|
86
|
+
@@states = {}
|
87
|
+
@@transitions = {}
|
88
|
+
@@bodies = {}
|
89
|
+
@@results = {}
|
90
|
+
|
91
|
+
def self.state(name, options)
|
92
|
+
if name.class==Array
|
93
|
+
name.each do |simple|
|
94
|
+
self.state(simple, options)
|
95
|
+
end
|
96
|
+
else
|
97
|
+
options[:allow] = [options[:allow]] unless options[:allow].class == Array
|
98
|
+
@@states[name] = options
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.transition(name, options = {}, result = nil, &body)
|
103
|
+
@@transitions[name] = options
|
104
|
+
@@bodies[name] = body
|
105
|
+
@@results[name] = result unless result == nil
|
106
|
+
defined = self.respond_to?(name)
|
107
|
+
if !defined
|
108
|
+
self.send(:define_method, name) do |*args|
|
109
|
+
self.status = result.to_s unless result == nil
|
110
|
+
end
|
111
|
+
self.send(:define_method, "can_#{name}2?") do
|
112
|
+
puts "executing can_#{name}2?"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
47
116
|
|
48
117
|
def self.add_states(result, states)
|
49
118
|
result._possible_states = {}
|
@@ -162,6 +231,7 @@ module ActiveRecord
|
|
162
231
|
h[key] = reflect_on_association(key.to_sym ).klass.from_hash value
|
163
232
|
end
|
164
233
|
end
|
234
|
+
h.delete("xmlns") if key=="xmlns"
|
165
235
|
end
|
166
236
|
result = self.new h
|
167
237
|
add_states(result, links) unless links.nil?
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: restfulie
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: "0.
|
4
|
+
version: "0.2"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Guilherme Silveira, Caue Guerra
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-11-
|
12
|
+
date: 2009-11-11 00:00:00 -02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|