acts_as_api 0.1.10 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,12 @@
1
+ === 0.2.1 2010-09-20
2
+
3
+ * Updated to work with Rails 3.0.0
4
+
5
+ * Added support for multiple renderings of the same model (e.g. useful for versioning).
6
+ Note that the interface of acts as api changed, soyou have to update your code.
7
+
8
+ * Updated dependecies to user Rails 3.0.0 libs instead of beta.
9
+
1
10
  === 0.1.10 2010-07-23
2
11
 
3
12
  * More Bugfixes. When you want to render an Array of records (e.g. from MyRecord.all)
@@ -19,6 +19,12 @@ acts_as_api uses the *default Rails serializers* for XML and JSON, so you don't
19
19
  mess around with even more dependencies. Once you change the serializers for your Rails app,
20
20
  they will be changed for acts_as_api too.
21
21
 
22
+ As of the version 0.2.0 it supports multiple api rendering templates for a models.
23
+ This is especially useful for API versioning or for example for private vs. public
24
+ access points to a user's profile.
25
+
26
+ *Note that upgrading to 0.2.0 will break code that worked with previous versions as you now have to specify an API template*
27
+
22
28
  == SYNOPSIS:
23
29
 
24
30
  === Set up your model
@@ -37,10 +43,13 @@ via the api, you would do something like this:
37
43
  acts_as_api
38
44
 
39
45
  # define the accessible attributes/methods for the api response
40
- api_accessible :firstname, :lastname
46
+ api_accessible :default => [ :firstname, :lastname ]
41
47
 
42
48
  end
43
49
 
50
+
51
+ An API template with the name +:default+ was created, see below how to use it in the controller:
52
+
44
53
  === Set up controller
45
54
 
46
55
  Now you just have to exchange the +render+ method in your controller for the +render_for_api+ method.
@@ -52,13 +61,14 @@ Now you just have to exchange the +render+ method in your controller for the +re
52
61
 
53
62
  respond_to do |format|
54
63
  format.html # show.html.erb
55
- format.xml { render_for_api :xml => @customer }
56
- format.json { render_for_api :json => @customer }
64
+ format.xml { render_for_api :default, :xml => @customer }
65
+ format.json { render_for_api :default, :json => @customer }
57
66
  end
58
67
  end
59
68
 
60
69
  end
61
70
 
71
+
62
72
  === That's it!
63
73
 
64
74
  Try it. The response should now look like this:
@@ -72,6 +82,80 @@ Try it. The response should now look like this:
72
82
  Other attributes of the model like +created_at+ or +updated_at+ won't be included because they were
73
83
  not listed by +api_accessible+ in the model.
74
84
 
85
+ == But you can do more...
86
+
87
+ === API Versioning
88
+
89
+ With the different named API templates, API versioning is pretty easy:
90
+
91
+ class User < ActiveRecord::Base
92
+
93
+ # let this model act as api!
94
+ acts_as_api
95
+
96
+ # define the accessible attributes/methods for the api response
97
+ api_accessible
98
+ :v1_public => [ :firstname, :age ],
99
+ :v2_public => [ :firstname, :age, :sex ],
100
+
101
+ :v1_private => [ :firstname, :lastname, :age, :sex ],
102
+ :v2_private => [ :firstname, :lastname, :age, :sex, :phone ]
103
+
104
+ end
105
+
106
+ Now you could create a method in the application controller of your app:
107
+
108
+ def api_template(version = :v2, template = :public)
109
+ "#{version.to_s}_#{template.to_s}".to_sym
110
+ end
111
+
112
+ And render the API responses:
113
+
114
+ class UsersController < ApplicationController
115
+
116
+ # renders the :v2_public template
117
+ def show
118
+ @user = User.find(params[:id])
119
+
120
+ respond_to do |format|
121
+ format.html # show.html.erb
122
+ format.xml { render_for_api api_template, :xml => @user }
123
+ format.json { render_for_api api_template, :json => @user }
124
+ end
125
+ end
126
+
127
+ # renders the :v1_private template
128
+ def profile_deprecated
129
+ @user = @current_user
130
+
131
+ respond_to do |format|
132
+ format.html # show.html.erb
133
+ format.xml { render_for_api api_template(:v1, :private), :xml => @user }
134
+ format.json { render_for_api api_template(:v1, :private), :json => @user }
135
+ end
136
+ end
137
+
138
+ end
139
+
140
+
141
+ === Metadata
142
+
143
+ You can include metadata elements in the response outside of your objects and collections. Typical usage for this is to include a total results count or page. Just pass in a :meta key with a hash of the meta items you want.
144
+
145
+ class CustomersController < ApplicationController
146
+
147
+ def index
148
+ @customers = Customer.paginate(:all, :page = params[:page])
149
+ metadata = { :total => @customers.total_entries, :page => params[:page] }
150
+ respond_to do |format|
151
+ format.html # show.html.erb
152
+ format.xml { render_for_api :default, :xml => @customer, :meta => metadata }
153
+ format.json { render_for_api :default, :json => @customer, :meta => metadata }
154
+ end
155
+ end
156
+
157
+ end
158
+
75
159
  === What can I include in my responses?
76
160
 
77
161
  You can do basically anything:
@@ -95,19 +179,20 @@ The model +Customer+ shows all kinds of ways to add data to your API response.
95
179
 
96
180
  # define the accessible attributes/methods for the api response
97
181
  # some attributes of the model
98
- api_accessible :firstname, :lastname, :age,
182
+ api_accessible :default => [ :firstname, :lastname, :age,
99
183
  # you can include methods
100
184
  :full_name,
101
185
  # include associated model in response
102
186
  :orders,
103
187
  # rename the node for orders
104
- :renamed_orders => :orders,
188
+ { :renamed_orders => :orders },
105
189
  # put orders in another subnode
106
- :subnode_orders => { :sub_oders => :orders },
190
+ { :subnode_orders => { :sub_oders => :orders } },
107
191
  # rename nodes/tag names
108
- :other_node => :say_something,
192
+ { :other_node => :say_something },
109
193
  # create a deeper node hierarchy
110
- :maybe => { :useful => { :for => :say_something } }
194
+ { :maybe => { :useful => { :for => :say_something } } }
195
+ ]
111
196
 
112
197
  # some example methods
113
198
  def full_name
@@ -131,9 +216,10 @@ The model +Order+ also acts as api and is even able to access a method of their
131
216
 
132
217
  # define the accessible attributes/methods for the api response
133
218
  # some attributes of the model
134
- api_accessible :city, :amount,
219
+ api_accessible :default => [ :city, :amount,
135
220
  #access a method of the parent association
136
- :parent_name => "customer.full_name"
221
+ { :parent_name => "customer.full_name" }
222
+ ]
137
223
 
138
224
  end
139
225
 
@@ -145,7 +231,7 @@ If you want a working example right out of the box, grab the example app: http:/
145
231
 
146
232
  == REQUIREMENTS:
147
233
 
148
- * Rails 3 beta 4
234
+ * Rails 3.0.0
149
235
 
150
236
  == INSTALL:
151
237
 
data/Rakefile CHANGED
@@ -14,7 +14,7 @@ $hoe = Hoe.spec 'acts_as_api' do
14
14
  self.developer 'Christian Bäuerlein', 'christian@ffwdme.com'
15
15
  #self.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
16
16
  #self.rubyforge_name = self.name # TODO this is default value
17
- self.extra_deps = [['activerecord','>= 3.0.0.beta4'], ['actionpack','>= 3.0.0.beta4']]
17
+ self.extra_deps = [['activerecord','>= 3.0.0'], ['actionpack','>= 3.0.0']]
18
18
 
19
19
  end
20
20
 
@@ -16,7 +16,7 @@ require "acts_as_api/array"
16
16
  # acts_as_api uses the default serializers of your rails app and doesn't
17
17
  # force you into more dependencies.
18
18
  module ActsAsApi
19
- VERSION = '0.1.10'
19
+ VERSION = '0.2.1'
20
20
 
21
21
  # The accepted response formats
22
22
  # Default is +[:xml, :json]+
@@ -43,7 +43,7 @@ if defined?(ActiveRecord::Base)
43
43
  ActiveRecord::Base.extend ActsAsApi::Base
44
44
  end
45
45
 
46
- # Attach ourselves to the abstract controller of rails
47
- if defined?(AbstractController::Rendering)
48
- AbstractController::Rendering.send :include, ActsAsApi::Rendering
46
+ # Attach ourselves to the action controller of rails
47
+ if defined?(ActionController::Base)
48
+ ActionController::Base.send :include, ActsAsApi::Rendering
49
49
  end
@@ -6,13 +6,13 @@ class Array
6
6
  # The Array checks all its items if they respond to the +as_api_response+ method.
7
7
  # If they do, the result of this method will be collected.
8
8
  # If they don't, the item itself will be collected.
9
- def as_api_response
9
+ def as_api_response(api_template)
10
10
 
11
11
  sub_items = []
12
12
 
13
13
  each do |item|
14
14
  if item.respond_to?(:as_api_response)
15
- sub_items << item.as_api_response
15
+ sub_items << item.as_api_response(api_template)
16
16
  else
17
17
  sub_items << item
18
18
  end
@@ -28,13 +28,15 @@ module ActsAsApi
28
28
  # *Note*: There is only whitelisting for api accessible attributes.
29
29
  # So once the model acts as api, you have to determine all attributes here that should
30
30
  # be contained in the api responses.
31
- def api_accessible(*attributes)
32
- write_inheritable_attribute(:api_accessible, Set.new(attributes) + (api_accessible_attributes || []))
31
+ def api_accessible(api_templates)
32
+ api_templates.each do |api_template, attributes|
33
+ write_inheritable_attribute("api_accessible_#{api_template}".to_sym, Set.new(attributes) + (api_accessible_attributes(api_template) || []))
34
+ end
33
35
  end
34
36
 
35
37
  # Returns an array of all the attributes that have been made accessible to the api response.
36
- def api_accessible_attributes
37
- read_inheritable_attribute(:api_accessible)
38
+ def api_accessible_attributes(api_template)
39
+ read_inheritable_attribute("api_accessible_#{api_template}".to_sym)
38
40
  end
39
41
 
40
42
  end
@@ -43,8 +45,8 @@ module ActsAsApi
43
45
  module InstanceMethods
44
46
 
45
47
  # Creates the api response of the model and returns it as a Hash.
46
- def as_api_response
47
- api_attributes = self.class.api_accessible_attributes
48
+ def as_api_response(api_template)
49
+ api_attributes = self.class.api_accessible_attributes(api_template)
48
50
 
49
51
  api_output = {}
50
52
 
@@ -59,7 +61,7 @@ module ActsAsApi
59
61
  out = send attribute
60
62
 
61
63
  if out.respond_to?(:as_api_response)
62
- out = out.send(:as_api_response)
64
+ out = out.send(:as_api_response, api_template)
63
65
  end
64
66
 
65
67
  api_output[attribute] = out
@@ -92,7 +94,7 @@ module ActsAsApi
92
94
  out = send v
93
95
 
94
96
  if out.respond_to?(:as_api_response)
95
- out = out.send(:as_api_response)
97
+ out = out.send(:as_api_response, api_template)
96
98
  end
97
99
 
98
100
  leaf[:parent][k] = out
@@ -117,13 +119,13 @@ module ActsAsApi
117
119
  end
118
120
 
119
121
  end
120
-
122
+
121
123
  end
122
124
 
123
125
  api_output
124
126
 
125
127
  end
126
-
128
+
127
129
  end
128
130
 
129
131
 
@@ -8,7 +8,7 @@ module ActsAsApi
8
8
  # to simply generate API outputs.
9
9
  #
10
10
  # The default Rails serializers are used to serialize the data.
11
- def render_for_api(render_options)
11
+ def render_for_api(api_template, render_options)
12
12
 
13
13
  # extract the api format and model
14
14
  api_format_options = {}
@@ -20,9 +20,10 @@ module ActsAsApi
20
20
  end
21
21
  end
22
22
 
23
+ meta_hash = render_options[:meta] if render_options.has_key?(:meta)
23
24
 
24
25
  api_format = api_format_options.keys.first
25
- api_model = api_format_options.values.first
26
+ api_model = api_format_options.values.first
26
27
 
27
28
  # set the params to render
28
29
  output_params = render_options
@@ -57,12 +58,14 @@ module ActsAsApi
57
58
  #output_params[:root] = output_params[:root].camelize if render_options.has_key?(:camelize) && render_options[:camelize]
58
59
  #output_params[:root] = output_params[:root].dasherize if !render_options.has_key?(:dasherize) || render_options[:dasherize]
59
60
 
60
- api_response = api_model.as_api_response
61
+ api_response = api_model.as_api_response(api_template)
61
62
 
62
- if ActsAsApi::ADD_ROOT_NODE_FOR.include? api_format
63
+ if meta_hash or ActsAsApi::ADD_ROOT_NODE_FOR.include? api_format
63
64
  api_response = { api_root_name.to_sym => api_response}
64
65
  end
65
66
 
67
+ api_response = meta_hash.merge api_response if meta_hash
68
+
66
69
  # create the Hash as response
67
70
  output_params[api_format] = api_response
68
71
 
@@ -71,5 +74,5 @@ module ActsAsApi
71
74
  end
72
75
 
73
76
  end
74
-
77
+
75
78
  end
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts_as_api
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 21
4
5
  prerelease: false
5
6
  segments:
6
7
  - 0
8
+ - 2
7
9
  - 1
8
- - 10
9
- version: 0.1.10
10
+ version: 0.2.1
10
11
  platform: ruby
11
12
  authors:
12
13
  - "Christian B\xC3\xA4uerlein"
@@ -14,46 +15,50 @@ autorequire:
14
15
  bindir: bin
15
16
  cert_chain: []
16
17
 
17
- date: 2010-07-23 00:00:00 +02:00
18
+ date: 2010-09-21 00:00:00 +02:00
18
19
  default_executable:
19
20
  dependencies:
20
21
  - !ruby/object:Gem::Dependency
21
22
  name: activerecord
22
23
  prerelease: false
23
24
  requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
24
26
  requirements:
25
27
  - - ">="
26
28
  - !ruby/object:Gem::Version
29
+ hash: 7
27
30
  segments:
28
31
  - 3
29
32
  - 0
30
33
  - 0
31
- - beta4
32
- version: 3.0.0.beta4
34
+ version: 3.0.0
33
35
  type: :runtime
34
36
  version_requirements: *id001
35
37
  - !ruby/object:Gem::Dependency
36
38
  name: actionpack
37
39
  prerelease: false
38
40
  requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
39
42
  requirements:
40
43
  - - ">="
41
44
  - !ruby/object:Gem::Version
45
+ hash: 7
42
46
  segments:
43
47
  - 3
44
48
  - 0
45
49
  - 0
46
- - beta4
47
- version: 3.0.0.beta4
50
+ version: 3.0.0
48
51
  type: :runtime
49
52
  version_requirements: *id002
50
53
  - !ruby/object:Gem::Dependency
51
54
  name: rubyforge
52
55
  prerelease: false
53
56
  requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
54
58
  requirements:
55
59
  - - ">="
56
60
  - !ruby/object:Gem::Version
61
+ hash: 7
57
62
  segments:
58
63
  - 2
59
64
  - 0
@@ -65,9 +70,11 @@ dependencies:
65
70
  name: hoe
66
71
  prerelease: false
67
72
  requirement: &id004 !ruby/object:Gem::Requirement
73
+ none: false
68
74
  requirements:
69
75
  - - ">="
70
76
  - !ruby/object:Gem::Version
77
+ hash: 21
71
78
  segments:
72
79
  - 2
73
80
  - 6
@@ -112,23 +119,27 @@ rdoc_options:
112
119
  require_paths:
113
120
  - lib
114
121
  required_ruby_version: !ruby/object:Gem::Requirement
122
+ none: false
115
123
  requirements:
116
124
  - - ">="
117
125
  - !ruby/object:Gem::Version
126
+ hash: 3
118
127
  segments:
119
128
  - 0
120
129
  version: "0"
121
130
  required_rubygems_version: !ruby/object:Gem::Requirement
131
+ none: false
122
132
  requirements:
123
133
  - - ">="
124
134
  - !ruby/object:Gem::Version
135
+ hash: 3
125
136
  segments:
126
137
  - 0
127
138
  version: "0"
128
139
  requirements: []
129
140
 
130
141
  rubyforge_project: acts_as_api
131
- rubygems_version: 1.3.6
142
+ rubygems_version: 1.3.7
132
143
  signing_key:
133
144
  specification_version: 3
134
145
  summary: acts_as_api makes creating XML/JSON responses in Rails 3 easy and fun.