activeresource 5.1.1 → 6.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +324 -0
- data/lib/active_resource/associations/builder/association.rb +1 -2
- data/lib/active_resource/associations.rb +2 -2
- data/lib/active_resource/base.rb +73 -36
- data/lib/active_resource/collection.rb +2 -2
- data/lib/active_resource/connection.rb +8 -5
- data/lib/active_resource/exceptions.rb +13 -3
- data/lib/active_resource/http_mock.rb +5 -7
- data/lib/active_resource/inheriting_hash.rb +15 -0
- data/lib/active_resource/railtie.rb +1 -1
- data/lib/active_resource/reflection.rb +2 -2
- data/lib/active_resource/schema.rb +1 -0
- data/lib/active_resource/singleton.rb +0 -2
- data/lib/active_resource/threadsafe_attributes.rb +0 -1
- data/lib/active_resource/validations.rb +5 -5
- data/lib/active_resource/version.rb +4 -4
- data/lib/active_resource.rb +1 -0
- metadata +32 -28
- data/README.rdoc +0 -285
- data/lib/active_resource/observing.rb +0 -0
data/README.rdoc
DELETED
@@ -1,285 +0,0 @@
|
|
1
|
-
= Active Resource
|
2
|
-
|
3
|
-
Active Resource (ARes) connects business objects and Representational State Transfer (REST)
|
4
|
-
web services. It implements object-relational mapping for REST web services to provide transparent
|
5
|
-
proxying capabilities between a client (ActiveResource) and a RESTful service (which is provided by Simply RESTful routing
|
6
|
-
in ActionController::Resources).
|
7
|
-
|
8
|
-
== Philosophy
|
9
|
-
|
10
|
-
Active Resource attempts to provide a coherent wrapper object-relational mapping for REST
|
11
|
-
web services. It follows the same philosophy as Active Record, in that one of its prime aims
|
12
|
-
is to reduce the amount of code needed to map to these resources. This is made possible
|
13
|
-
by relying on a number of code- and protocol-based conventions that make it easy for Active Resource
|
14
|
-
to infer complex relations and structures. These conventions are outlined in detail in the documentation
|
15
|
-
for ActiveResource::Base.
|
16
|
-
|
17
|
-
== Overview
|
18
|
-
|
19
|
-
Model classes are mapped to remote REST resources by Active Resource much the same way Active Record maps model classes to database
|
20
|
-
tables. When a request is made to a remote resource, a REST JSON request is generated, transmitted, and the result
|
21
|
-
received and serialized into a usable Ruby object.
|
22
|
-
|
23
|
-
== Download and installation
|
24
|
-
|
25
|
-
The latest version of Active Resource can be installed with RubyGems:
|
26
|
-
|
27
|
-
% [sudo] gem install activeresource
|
28
|
-
|
29
|
-
Or added to a Gemfile:
|
30
|
-
|
31
|
-
gem 'activeresource'
|
32
|
-
|
33
|
-
Source code can be downloaded on GitHub
|
34
|
-
|
35
|
-
* https://github.com/rails/activeresource/tree/master/activeresource
|
36
|
-
|
37
|
-
=== Configuration and Usage
|
38
|
-
|
39
|
-
Putting Active Resource to use is very similar to Active Record. It's as simple as creating a model class
|
40
|
-
that inherits from ActiveResource::Base and providing a <tt>site</tt> class variable to it:
|
41
|
-
|
42
|
-
class Person < ActiveResource::Base
|
43
|
-
self.site = "http://api.people.com:3000"
|
44
|
-
end
|
45
|
-
|
46
|
-
Now the Person class is REST enabled and can invoke REST services very similarly to how Active Record invokes
|
47
|
-
life cycle methods that operate against a persistent store.
|
48
|
-
|
49
|
-
# Find a person with id = 1
|
50
|
-
tyler = Person.find(1)
|
51
|
-
Person.exists?(1) # => true
|
52
|
-
|
53
|
-
As you can see, the methods are quite similar to Active Record's methods for dealing with database
|
54
|
-
records. But rather than dealing directly with a database record, you're dealing with HTTP resources (which may or may not be database records).
|
55
|
-
|
56
|
-
Connection settings (`site`, `headers`, `user`, `password`, `proxy`) and the connections themselves are store in
|
57
|
-
thread-local variables to make them thread-safe, so you can also set these dynamically, even in a multi-threaded environment, for instance:
|
58
|
-
|
59
|
-
ActiveResource::Base.site = api_site_for(request)
|
60
|
-
|
61
|
-
==== Authentication
|
62
|
-
|
63
|
-
Active Resource supports the token based authentication provided by Rails through the <tt>ActionController::HttpAuthentication::Token</tt> class using custom headers.
|
64
|
-
|
65
|
-
class Person < ActiveResource::Base
|
66
|
-
self.headers['Authorization'] = 'Token token="abcd"'
|
67
|
-
end
|
68
|
-
|
69
|
-
You can also set any specific HTTP header using the same way. As mentioned above, headers are thread-safe, so you can set headers dynamically, even in a multi-threaded environment:
|
70
|
-
|
71
|
-
ActiveResource::Base.headers['Authorization'] = current_session_api_token
|
72
|
-
|
73
|
-
Global Authentication to be used across all subclasses of ActiveResource::Base should be handled using the ActiveResource::Connection class.
|
74
|
-
|
75
|
-
ActiveResource::Base.connection.auth_type = :bearer
|
76
|
-
ActiveResource::Base.connection.bearer_token = @bearer_token
|
77
|
-
|
78
|
-
class Person < ActiveResource::Base
|
79
|
-
self.connection.auth_type = :bearer
|
80
|
-
self.connection.bearer_token = @bearer_token
|
81
|
-
end
|
82
|
-
|
83
|
-
ActiveResource supports 2 options for HTTP authentication today.
|
84
|
-
|
85
|
-
1. Basic
|
86
|
-
|
87
|
-
ActiveResource::Connection.new("http://my%40email.com:%31%32%33@localhost")
|
88
|
-
# username: my@email.com password: 123
|
89
|
-
|
90
|
-
2. Bearer Token
|
91
|
-
|
92
|
-
ActiveResource::Base.connection.auth_type = :bearer
|
93
|
-
ActiveResource::Base.connection.bearer_token = @bearer_token
|
94
|
-
|
95
|
-
==== Protocol
|
96
|
-
|
97
|
-
Active Resource is built on a standard JSON or XML format for requesting and submitting resources over HTTP. It mirrors the RESTful routing
|
98
|
-
built into Action Controller but will also work with any other REST service that properly implements the protocol.
|
99
|
-
REST uses HTTP, but unlike "typical" web applications, it makes use of all the verbs available in the HTTP specification:
|
100
|
-
|
101
|
-
* GET requests are used for finding and retrieving resources.
|
102
|
-
* POST requests are used to create new resources.
|
103
|
-
* PUT requests are used to update existing resources.
|
104
|
-
* DELETE requests are used to delete resources.
|
105
|
-
|
106
|
-
For more information on how this protocol works with Active Resource, see the ActiveResource::Base documentation;
|
107
|
-
for more general information on REST web services, see the article here[http://en.wikipedia.org/wiki/Representational_State_Transfer].
|
108
|
-
|
109
|
-
==== Find
|
110
|
-
|
111
|
-
Find requests use the GET method and expect the JSON form of whatever resource/resources is/are being requested. So,
|
112
|
-
for a request for a single element, the JSON of that item is expected in response:
|
113
|
-
|
114
|
-
# Expects a response of
|
115
|
-
#
|
116
|
-
# {"id":1,"first":"Tyler","last":"Durden"}
|
117
|
-
#
|
118
|
-
# for GET http://api.people.com:3000/people/1.json
|
119
|
-
#
|
120
|
-
tyler = Person.find(1)
|
121
|
-
|
122
|
-
The JSON document that is received is used to build a new object of type Person, with each
|
123
|
-
JSON element becoming an attribute on the object.
|
124
|
-
|
125
|
-
tyler.is_a? Person # => true
|
126
|
-
tyler.last # => 'Durden'
|
127
|
-
|
128
|
-
Any complex element (one that contains other elements) becomes its own object:
|
129
|
-
|
130
|
-
# With this response:
|
131
|
-
# {"id":1,"first":"Tyler","address":{"street":"Paper St.","state":"CA"}}
|
132
|
-
#
|
133
|
-
# for GET http://api.people.com:3000/people/1.json
|
134
|
-
#
|
135
|
-
tyler = Person.find(1)
|
136
|
-
tyler.address # => <Person::Address::xxxxx>
|
137
|
-
tyler.address.street # => 'Paper St.'
|
138
|
-
|
139
|
-
Collections can also be requested in a similar fashion
|
140
|
-
|
141
|
-
# Expects a response of
|
142
|
-
#
|
143
|
-
# [
|
144
|
-
# {"id":1,"first":"Tyler","last":"Durden"},
|
145
|
-
# {"id":2,"first":"Tony","last":"Stark",}
|
146
|
-
# ]
|
147
|
-
#
|
148
|
-
# for GET http://api.people.com:3000/people.json
|
149
|
-
#
|
150
|
-
people = Person.all
|
151
|
-
people.first # => <Person::xxx 'first' => 'Tyler' ...>
|
152
|
-
people.last # => <Person::xxx 'first' => 'Tony' ...>
|
153
|
-
|
154
|
-
==== Create
|
155
|
-
|
156
|
-
Creating a new resource submits the JSON form of the resource as the body of the request and expects
|
157
|
-
a 'Location' header in the response with the RESTful URL location of the newly created resource. The
|
158
|
-
id of the newly created resource is parsed out of the Location response header and automatically set
|
159
|
-
as the id of the ARes object.
|
160
|
-
|
161
|
-
# {"first":"Tyler","last":"Durden"}
|
162
|
-
#
|
163
|
-
# is submitted as the body on
|
164
|
-
#
|
165
|
-
# if include_root_in_json is not set or set to false => {"first":"Tyler"}
|
166
|
-
# if include_root_in_json is set to true => {"person":{"first":"Tyler"}}
|
167
|
-
#
|
168
|
-
# POST http://api.people.com:3000/people.json
|
169
|
-
#
|
170
|
-
# when save is called on a new Person object. An empty response is
|
171
|
-
# is expected with a 'Location' header value:
|
172
|
-
#
|
173
|
-
# Response (201): Location: http://api.people.com:3000/people/2
|
174
|
-
#
|
175
|
-
tyler = Person.new(:first => 'Tyler')
|
176
|
-
tyler.new? # => true
|
177
|
-
tyler.save # => true
|
178
|
-
tyler.new? # => false
|
179
|
-
tyler.id # => 2
|
180
|
-
|
181
|
-
==== Update
|
182
|
-
|
183
|
-
'save' is also used to update an existing resource and follows the same protocol as creating a resource
|
184
|
-
with the exception that no response headers are needed -- just an empty response when the update on the
|
185
|
-
server side was successful.
|
186
|
-
|
187
|
-
# {"first":"Tyler"}
|
188
|
-
#
|
189
|
-
# is submitted as the body on
|
190
|
-
#
|
191
|
-
# if include_root_in_json is not set or set to false => {"first":"Tyler"}
|
192
|
-
# if include_root_in_json is set to true => {"person":{"first":"Tyler"}}
|
193
|
-
#
|
194
|
-
# PUT http://api.people.com:3000/people/1.json
|
195
|
-
#
|
196
|
-
# when save is called on an existing Person object. An empty response is
|
197
|
-
# is expected with code (204)
|
198
|
-
#
|
199
|
-
tyler = Person.find(1)
|
200
|
-
tyler.first # => 'Tyler'
|
201
|
-
tyler.first = 'Tyson'
|
202
|
-
tyler.save # => true
|
203
|
-
|
204
|
-
==== Delete
|
205
|
-
|
206
|
-
Destruction of a resource can be invoked as a class and instance method of the resource.
|
207
|
-
|
208
|
-
# A request is made to
|
209
|
-
#
|
210
|
-
# DELETE http://api.people.com:3000/people/1.json
|
211
|
-
#
|
212
|
-
# for both of these forms. An empty response with
|
213
|
-
# is expected with response code (200)
|
214
|
-
#
|
215
|
-
tyler = Person.find(1)
|
216
|
-
tyler.destroy # => true
|
217
|
-
tyler.exists? # => false
|
218
|
-
Person.delete(2) # => true
|
219
|
-
Person.exists?(2) # => false
|
220
|
-
|
221
|
-
==== Associations
|
222
|
-
|
223
|
-
Relationships between resources can be declared using the standard association syntax
|
224
|
-
that should be familiar to anyone who uses activerecord. For example, using the
|
225
|
-
class definition below:
|
226
|
-
|
227
|
-
class Post < ActiveResource::Base
|
228
|
-
self.site = "http://blog.io"
|
229
|
-
has_many :comments
|
230
|
-
end
|
231
|
-
|
232
|
-
post = Post.find(1) # issues GET http://blog.io/posts/1.json
|
233
|
-
comments = post.comments # issues GET http://blog.io/comments.json?post_id=1
|
234
|
-
|
235
|
-
|
236
|
-
If you control the server, you may wish to include nested resources thus avoiding a
|
237
|
-
second network request. Given the resource above, if the response includes comments
|
238
|
-
in the response, they will be automatically loaded into the activeresource object.
|
239
|
-
The server-side model can be adjusted as follows to include comments in the response.
|
240
|
-
|
241
|
-
class Post < ActiveRecord::Base
|
242
|
-
has_many :comments
|
243
|
-
|
244
|
-
def as_json(options)
|
245
|
-
super.merge(:include=>[:comments])
|
246
|
-
end
|
247
|
-
end
|
248
|
-
|
249
|
-
==== Logging
|
250
|
-
|
251
|
-
Active Resource instruments the event `request.active_resource` when doing a request
|
252
|
-
to the remote service. You can subscribe to it by doing:
|
253
|
-
|
254
|
-
ActiveSupport::Notifications.subscribe('request.active_resource') do |name, start, finish, id, payload|
|
255
|
-
|
256
|
-
The `payload` is a `Hash` with the following keys:
|
257
|
-
|
258
|
-
* `method` as a `Symbol`
|
259
|
-
* `request_uri` as a `String`
|
260
|
-
* `result` as an `Net::HTTPResponse`
|
261
|
-
|
262
|
-
== License
|
263
|
-
|
264
|
-
Active Resource is released under the MIT license:
|
265
|
-
|
266
|
-
* http://www.opensource.org/licenses/MIT
|
267
|
-
|
268
|
-
== Contributing to Active Resource
|
269
|
-
|
270
|
-
Active Resource is work of many contributors. You're encouraged to submit pull requests, propose
|
271
|
-
features and discuss issues.
|
272
|
-
|
273
|
-
See {CONTRIBUTING}[https://github.com/rails/activeresource/blob/master/CONTRIBUTING.md].
|
274
|
-
|
275
|
-
== Support
|
276
|
-
|
277
|
-
Full API documentation is available at
|
278
|
-
|
279
|
-
* http://rubydoc.info/gems/activeresource
|
280
|
-
|
281
|
-
Bug reports and feature requests can be filed with the rest for the Ruby on Rails project here:
|
282
|
-
|
283
|
-
* https://github.com/rails/activeresource/issues
|
284
|
-
|
285
|
-
You can find more usage information in the ActiveResource::Base documentation.
|
File without changes
|