activeresource 3.2.22.5 → 4.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activeresource might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 480213fdf4278e17032edc702ac6a382fed5e257
4
- data.tar.gz: d99d3c4519997be684c92b0d877f2d2126a54ede
3
+ metadata.gz: 931c2a3ac5d3c4b76c2165a6d58c44f4aedab23e
4
+ data.tar.gz: 1a3056f9e297d082f97bdb7350023c571c3dc79d
5
5
  SHA512:
6
- metadata.gz: 074be6f00e06d0bb0af86e772c95e287b65da977010f7e11eca2bc72e68e64612e62abbd24980cfa612f0db33703ee0c306bfea1ed21bc323997633085cc86ee
7
- data.tar.gz: 71bf71e63a3037ec3e145282b4ef4c1d6fcf7eaf067ef4ceec75cfde85ea389d8bdb66b764e8e0bd7a181ec0e16a6214eb5a41221d11fb946d0d7c470df6e83c
6
+ metadata.gz: 459d6c6a88802add4531118ac6f9191c27196e805be61f35e60787a8fc4a4b380cf456c459a63f6f4c6d9c83f8397dec1fdb9d70f8265c2a8358c978dc919d70
7
+ data.tar.gz: 05bea224b9115b0ab07cdf8c18846b7327ccabf4265d889ee6caff0437a4349de9f68b9e249c5a8679551001da05322a08b28d5cfcf9dee90c12ae4a6a3fa4d4
@@ -1,4 +1,4 @@
1
- = Active Resource
1
+ = Active Resource {<img src="https://secure.travis-ci.org/rails/activeresource.png" />}[http://travis-ci.org/rails/activeresource]
2
2
 
3
3
  Active Resource (ARes) connects business objects and Representational State Transfer (REST)
4
4
  web services. It implements object-relational mapping for REST web services to provide transparent
@@ -17,7 +17,7 @@ for ActiveResource::Base.
17
17
  == Overview
18
18
 
19
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 XML request is generated, transmitted, and the result
20
+ tables. When a request is made to a remote resource, a REST JSON request is generated, transmitted, and the result
21
21
  received and serialized into a usable Ruby object.
22
22
 
23
23
  == Download and installation
@@ -26,9 +26,13 @@ The latest version of Active Resource can be installed with RubyGems:
26
26
 
27
27
  % [sudo] gem install activeresource
28
28
 
29
- Source code can be downloaded as part of the Rails project on GitHub
29
+ Or added to a Gemfile:
30
30
 
31
- * https://github.com/rails/rails/tree/3-2-stable/activeresource
31
+ gem 'activeresource', :require => 'active_resource'
32
+
33
+ Source code can be downloaded on GitHub
34
+
35
+ * https://github.com/rails/activeresource/tree/master/activeresource
32
36
 
33
37
  === Configuration and Usage
34
38
 
@@ -43,7 +47,7 @@ Now the Person class is REST enabled and can invoke REST services very similarly
43
47
  life cycle methods that operate against a persistent store.
44
48
 
45
49
  # Find a person with id = 1
46
- ryan = Person.find(1)
50
+ tyler = Person.find(1)
47
51
  Person.exists?(1) # => true
48
52
 
49
53
  As you can see, the methods are quite similar to Active Record's methods for dealing with database
@@ -51,7 +55,7 @@ records. But rather than dealing directly with a database record, you're dealin
51
55
 
52
56
  ==== Protocol
53
57
 
54
- Active Resource is built on a standard XML format for requesting and submitting resources over HTTP. It mirrors the RESTful routing
58
+ Active Resource is built on a standard JSON or XML format for requesting and submitting resources over HTTP. It mirrors the RESTful routing
55
59
  built into Action Controller but will also work with any other REST service that properly implements the protocol.
56
60
  REST uses HTTP, but unlike "typical" web applications, it makes use of all the verbs available in the HTTP specification:
57
61
 
@@ -65,73 +69,72 @@ for more general information on REST web services, see the article here[http://e
65
69
 
66
70
  ==== Find
67
71
 
68
- Find requests use the GET method and expect the XML form of whatever resource/resources is/are being requested. So,
69
- for a request for a single element, the XML of that item is expected in response:
72
+ Find requests use the GET method and expect the JSON form of whatever resource/resources is/are being requested. So,
73
+ for a request for a single element, the JSON of that item is expected in response:
70
74
 
71
75
  # Expects a response of
72
76
  #
73
- # <person><id type="integer">1</id><attribute1>value1</attribute1><attribute2>..</attribute2></person>
77
+ # {"id":1,"first":"Tyler","last":"Durden"}
74
78
  #
75
- # for GET http://api.people.com:3000/people/1.xml
79
+ # for GET http://api.people.com:3000/people/1.json
76
80
  #
77
- ryan = Person.find(1)
81
+ tyler = Person.find(1)
78
82
 
79
- The XML document that is received is used to build a new object of type Person, with each
80
- XML element becoming an attribute on the object.
83
+ The JSON document that is received is used to build a new object of type Person, with each
84
+ JSON element becoming an attribute on the object.
81
85
 
82
- ryan.is_a? Person # => true
83
- ryan.attribute1 # => 'value1'
86
+ tyler.is_a? Person # => true
87
+ tyler.last # => 'Durden'
84
88
 
85
89
  Any complex element (one that contains other elements) becomes its own object:
86
90
 
87
91
  # With this response:
92
+ # {"id":1,"first":"Tyler","address":{"street":"Paper St.","state":"CA"}}
88
93
  #
89
- # <person><id>1</id><attribute1>value1</attribute1><complex><attribute2>value2</attribute2></complex></person>
94
+ # for GET http://api.people.com:3000/people/1.json
90
95
  #
91
- # for GET http://api.people.com:3000/people/1.xml
92
- #
93
- ryan = Person.find(1)
94
- ryan.complex # => <Person::Complex::xxxxx>
95
- ryan.complex.attribute2 # => 'value2'
96
+ tyler = Person.find(1)
97
+ tyler.address # => <Person::Address::xxxxx>
98
+ tyler.address.street # => 'Paper St.'
96
99
 
97
100
  Collections can also be requested in a similar fashion
98
101
 
99
102
  # Expects a response of
100
103
  #
101
- # <people type="array">
102
- # <person><id type="integer">1</id><first>Ryan</first></person>
103
- # <person><id type="integer">2</id><first>Jim</first></person>
104
- # </people>
104
+ # [
105
+ # {"id":1,"first":"Tyler","last":"Durden"},
106
+ # {"id":2,"first":"Tony","last":"Stark",}
107
+ # ]
105
108
  #
106
- # for GET http://api.people.com:3000/people.xml
109
+ # for GET http://api.people.com:3000/people.json
107
110
  #
108
111
  people = Person.all
109
- people.first # => <Person::xxx 'first' => 'Ryan' ...>
110
- people.last # => <Person::xxx 'first' => 'Jim' ...>
112
+ people.first # => <Person::xxx 'first' => 'Tyler' ...>
113
+ people.last # => <Person::xxx 'first' => 'Tony' ...>
111
114
 
112
115
  ==== Create
113
116
 
114
- Creating a new resource submits the XML form of the resource as the body of the request and expects
117
+ Creating a new resource submits the JSON form of the resource as the body of the request and expects
115
118
  a 'Location' header in the response with the RESTful URL location of the newly created resource. The
116
119
  id of the newly created resource is parsed out of the Location response header and automatically set
117
120
  as the id of the ARes object.
118
121
 
119
- # <person><first>Ryan</first></person>
122
+ # {"person":{"first":"Tyler","last":"Durden"}}
120
123
  #
121
124
  # is submitted as the body on
122
125
  #
123
- # POST http://api.people.com:3000/people.xml
126
+ # POST http://api.people.com:3000/people.json
124
127
  #
125
128
  # when save is called on a new Person object. An empty response is
126
129
  # is expected with a 'Location' header value:
127
130
  #
128
131
  # Response (201): Location: http://api.people.com:3000/people/2
129
132
  #
130
- ryan = Person.new(:first => 'Ryan')
131
- ryan.new? # => true
132
- ryan.save # => true
133
- ryan.new? # => false
134
- ryan.id # => 2
133
+ tyler = Person.new(:first => 'Tyler')
134
+ tyler.new? # => true
135
+ tyler.save # => true
136
+ tyler.new? # => false
137
+ tyler.id # => 2
135
138
 
136
139
  ==== Update
137
140
 
@@ -139,19 +142,19 @@ as the id of the ARes object.
139
142
  with the exception that no response headers are needed -- just an empty response when the update on the
140
143
  server side was successful.
141
144
 
142
- # <person><first>Ryan</first></person>
145
+ # {"person":{"first":"Tyler"}}
143
146
  #
144
147
  # is submitted as the body on
145
148
  #
146
- # PUT http://api.people.com:3000/people/1.xml
149
+ # PUT http://api.people.com:3000/people/1.json
147
150
  #
148
151
  # when save is called on an existing Person object. An empty response is
149
152
  # is expected with code (204)
150
153
  #
151
- ryan = Person.find(1)
152
- ryan.first # => 'Ryan'
153
- ryan.first = 'Rizzle'
154
- ryan.save # => true
154
+ tyler = Person.find(1)
155
+ tyler.first # => 'Tyler'
156
+ tyler.first = 'Tyson'
157
+ tyler.save # => true
155
158
 
156
159
  ==== Delete
157
160
 
@@ -159,20 +162,22 @@ Destruction of a resource can be invoked as a class and instance method of the r
159
162
 
160
163
  # A request is made to
161
164
  #
162
- # DELETE http://api.people.com:3000/people/1.xml
165
+ # DELETE http://api.people.com:3000/people/1.json
163
166
  #
164
167
  # for both of these forms. An empty response with
165
168
  # is expected with response code (200)
166
169
  #
167
- ryan = Person.find(1)
168
- ryan.destroy # => true
169
- ryan.exists? # => false
170
+ tyler = Person.find(1)
171
+ tyler.destroy # => true
172
+ tyler.exists? # => false
170
173
  Person.delete(2) # => true
171
174
  Person.exists?(2) # => false
172
175
 
173
176
  == License
174
177
 
175
- Active Resource is released under the MIT license.
178
+ Active Resource is released under the MIT license:
179
+
180
+ * http://www.opensource.org/licenses/MIT
176
181
 
177
182
  == Support
178
183
 
@@ -182,6 +187,6 @@ API documentation is at
182
187
 
183
188
  Bug reports and feature requests can be filed with the rest for the Ruby on Rails project here:
184
189
 
185
- * https://github.com/rails/rails/issues
190
+ * https://github.com/rails/activeresource/issues
186
191
 
187
192
  You can find more usage information in the ActiveResource::Base documentation.
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2006-2011 David Heinemeier Hansson
2
+ # Copyright (c) 2006-2012 David Heinemeier Hansson
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -21,12 +21,6 @@
21
21
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
22
  #++
23
23
 
24
- activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
25
- $:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
26
-
27
- activemodel_path = File.expand_path('../../../activemodel/lib', __FILE__)
28
- $:.unshift(activemodel_path) if File.directory?(activemodel_path) && !$:.include?(activemodel_path)
29
-
30
24
  require 'active_support'
31
25
  require 'active_model'
32
26
  require 'active_resource/exceptions'
@@ -36,11 +30,14 @@ module ActiveResource
36
30
  extend ActiveSupport::Autoload
37
31
 
38
32
  autoload :Base
33
+ autoload :Callbacks
39
34
  autoload :Connection
40
35
  autoload :CustomMethods
41
36
  autoload :Formats
42
37
  autoload :HttpMock
43
38
  autoload :Observing
44
39
  autoload :Schema
40
+ autoload :Singleton
45
41
  autoload :Validations
42
+ autoload :Collection
46
43
  end
@@ -0,0 +1,168 @@
1
+ module ActiveResource::Associations
2
+
3
+ module Builder
4
+ autoload :Association, 'active_resource/associations/builder/association'
5
+ autoload :HasMany, 'active_resource/associations/builder/has_many'
6
+ autoload :HasOne, 'active_resource/associations/builder/has_one'
7
+ autoload :BelongsTo, 'active_resource/associations/builder/belongs_to'
8
+ end
9
+
10
+
11
+
12
+ # Specifies a one-to-many association.
13
+ #
14
+ # === Options
15
+ # [:class_name]
16
+ # Specify the class name of the association. This class name would
17
+ # be used for resolving the association class.
18
+ #
19
+ # ==== Example for [:class_name] - option
20
+ # GET /posts/123.json delivers following response body:
21
+ # {
22
+ # title: "ActiveResource now has associations",
23
+ # body: "Lorem Ipsum"
24
+ # comments: [
25
+ # {
26
+ # content: "..."
27
+ # },
28
+ # {
29
+ # content: "..."
30
+ # }
31
+ # ]
32
+ # }
33
+ # ====
34
+ #
35
+ # <tt>has_many :comments, :class_name => 'myblog/comment'</tt>
36
+ # Would resolve those comments into the <tt>Myblog::Comment</tt> class.
37
+ #
38
+ # If the response body does not contain an attribute matching the association name
39
+ # a request sent to the index action under the current resource.
40
+ # For the example above, if the comments are not present the requested path would be:
41
+ # GET /posts/123/comments.xml
42
+ def has_many(name, options = {})
43
+ Builder::HasMany.build(self, name, options)
44
+ end
45
+
46
+ # Specifies a one-to-one association.
47
+ #
48
+ # === Options
49
+ # [:class_name]
50
+ # Specify the class name of the association. This class name would
51
+ # be used for resolving the association class.
52
+ #
53
+ # ==== Example for [:class_name] - option
54
+ # GET /posts/1.json delivers following response body:
55
+ # {
56
+ # title: "ActiveResource now has associations",
57
+ # body: "Lorem Ipsum",
58
+ # author: {
59
+ # name: "Gabby Blogger",
60
+ # }
61
+ # }
62
+ # ====
63
+ #
64
+ # <tt>has_one :author, :class_name => 'myblog/author'</tt>
65
+ # Would resolve this author into the <tt>Myblog::Author</tt> class.
66
+ #
67
+ # If the response body does not contain an attribute matching the association name
68
+ # a request is sent to a singelton path under the current resource.
69
+ # For example, if a Product class <tt>has_one :inventory</tt> calling <tt>Product#inventory</tt>
70
+ # will generate a request on /product/:product_id/inventory.json.
71
+ #
72
+ def has_one(name, options = {})
73
+ Builder::HasOne.build(self, name, options)
74
+ end
75
+
76
+ # Specifies a one-to-one association with another class. This class should only be used
77
+ # if this class contains the foreign key.
78
+ #
79
+ # Methods will be added for retrieval and query for a single associated object, for which
80
+ # this object holds an id:
81
+ #
82
+ # [association(force_reload = false)]
83
+ # Returns the associated object. +nil+ is returned if the foreign key is +nil+.
84
+ # Throws a ActiveResource::ResourceNotFound exception if the foreign key is not +nil+
85
+ # and the resource is not found.
86
+ #
87
+ # (+association+ is replaced with the symbol passed as the first argument, so
88
+ # <tt>belongs_to :post</tt> would add among others <tt>post.nil?</tt>.
89
+ #
90
+ # === Example
91
+ #
92
+ # A Comment class declaress <tt>belongs_to :post</tt>, which will add:
93
+ # * <tt>Comment#post</tt> (similar to <tt>Post.find(post_id)</tt>)
94
+ # The declaration can also include an options hash to specialize the behavior of the association.
95
+ #
96
+ # === Options
97
+ # [:class_name]
98
+ # Specify the class name for the association. Use it only if that name canÄt be inferred from association name.
99
+ # So <tt>belongs_to :post</tt> will by default be linked to the Post class, but if the real class name is Article,
100
+ # you'll have to specify it with whis option.
101
+ # [:foreign_key]
102
+ # Specify the foreign key used for the association. By default this is guessed to be the name
103
+ # of the association with an "_id" suffix. So a class that defines a <tt>belongs_to :post</tt>
104
+ # association will use "post_id" as the default <tt>:foreign_key</tt>. Similarly,
105
+ # <tt>belongs_to :article, :class_name => "Post"</tt> will use a foreign key
106
+ # of "article_id".
107
+ #
108
+ # Option examples:
109
+ # <tt>belongs_to :customer, :class_name => 'User'</tt>
110
+ # Creates a belongs_to association called customer which is represented through the <tt>User</tt> class.
111
+ #
112
+ # <tt>belongs_to :customer, :foreign_key => 'user_id'</tt>
113
+ # Creates a belongs_to association called customer which would be resolved by the foreign_key <tt>user_id</tt> instead of <tt>customer_id</tt>
114
+ #
115
+ def belongs_to(name, options={})
116
+ Builder::BelongsTo.build(self, name, options)
117
+ end
118
+
119
+ # Defines the belongs_to association finder method
120
+ def defines_belongs_to_finder_method(method_name, association_model, finder_key)
121
+ ivar_name = :"@#{method_name}"
122
+
123
+ if method_defined?(method_name)
124
+ instance_variable_set(ivar_name, nil)
125
+ remove_method(method_name)
126
+ end
127
+
128
+ define_method(method_name) do
129
+ if instance_variable_defined?(ivar_name)
130
+ instance_variable_get(ivar_name)
131
+ elsif attributes.include?(method_name)
132
+ attributes[method_name]
133
+ else
134
+ instance_variable_set(ivar_name, association_model.find(send(finder_key)))
135
+ end
136
+ end
137
+ end
138
+
139
+ def defines_has_many_finder_method(method_name, association_model)
140
+ ivar_name = :"@#{method_name}"
141
+
142
+ define_method(method_name) do
143
+ if instance_variable_defined?(ivar_name)
144
+ instance_variable_get(ivar_name)
145
+ elsif attributes.include?(method_name)
146
+ attributes[method_name]
147
+ else
148
+ instance_variable_set(ivar_name, association_model.find(:all, :params => {:"#{self.class.element_name}_id" => self.id}))
149
+ end
150
+ end
151
+ end
152
+
153
+ # Defines the has_one association
154
+ def defines_has_one_finder_method(method_name, association_model)
155
+ ivar_name = :"@#{method_name}"
156
+
157
+ define_method(method_name) do
158
+ if instance_variable_defined?(ivar_name)
159
+ instance_variable_get(ivar_name)
160
+ elsif attributes.include?(method_name)
161
+ attributes[method_name]
162
+ else
163
+ instance_variable_set(ivar_name, association_model.find(:params => {:"#{self.class.element_name}_id" => self.id}))
164
+ end
165
+ end
166
+ end
167
+
168
+ end
@@ -0,0 +1,32 @@
1
+ module ActiveResource::Associations::Builder
2
+ class Association #:nodoc:
3
+
4
+ # providing a Class-Variable, which will have a different store of subclasses
5
+ class_attribute :valid_options
6
+ self.valid_options = [:class_name]
7
+
8
+ # would identify subclasses of association
9
+ class_attribute :macro
10
+
11
+ attr_reader :model, :name, :options, :klass
12
+
13
+ def self.build(model, name, options)
14
+ new(model, name, options).build
15
+ end
16
+
17
+ def initialize(model, name, options)
18
+ @model, @name, @options = model, name, options
19
+ end
20
+
21
+ def build
22
+ validate_options
23
+ model.create_reflection(self.class.macro, name, options)
24
+ end
25
+
26
+ private
27
+
28
+ def validate_options
29
+ options.assert_valid_keys(self.class.valid_options)
30
+ end
31
+ end
32
+ end