acts_as_api 0.3.2 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +15 -1
- data/README.rdoc +3 -0
- data/lib/acts_as_api/api_template.rb +118 -12
- data/lib/acts_as_api/array.rb +1 -1
- data/lib/acts_as_api/base.rb +8 -67
- data/lib/acts_as_api/config.rb +4 -0
- data/lib/acts_as_api/rails_renderer.rb +3 -1
- data/lib/acts_as_api/version.rb +1 -2
- data/lib/acts_as_api.rb +2 -3
- data/spec/controllers/users_controller_spec.rb +4 -5
- data/spec/models/base/associations_spec.rb +284 -0
- data/spec/models/base/closures_spec.rb +62 -0
- data/spec/models/base/conditional_if_spec.rb +178 -0
- data/spec/models/base/conditional_unless_spec.rb +178 -0
- data/spec/models/base/enabled_spec.rb +15 -0
- data/spec/models/base/extending_spec.rb +74 -0
- data/spec/models/base/methods_spec.rb +33 -0
- data/spec/models/base/renaming_spec.rb +63 -0
- data/spec/models/base/simple_spec.rb +33 -0
- data/spec/models/base/sub_nodes_spec.rb +118 -0
- data/spec/models/base/undefined_spec.rb +20 -0
- data/spec/models/base/untouched_spec.rb +18 -0
- data/spec/rails_app/app/models/user.rb +52 -0
- data/spec/support/simple_fixtures.rb +26 -0
- metadata +30 -6
- data/spec/models/base_spec.rb +0 -635
data/History.txt
CHANGED
@@ -1,4 +1,18 @@
|
|
1
|
-
=== 0.3.
|
1
|
+
=== 0.3.3 2011-04-24
|
2
|
+
|
3
|
+
* Added support for :if and :unless options
|
4
|
+
|
5
|
+
=== 0.3.2 2011-04-20
|
6
|
+
|
7
|
+
* Raise an exception if a specified api template is not found
|
8
|
+
|
9
|
+
=== 0.3.1 2011-04-08
|
10
|
+
|
11
|
+
* Added the :template option to specify sub templates
|
12
|
+
|
13
|
+
* Fixed a bug concerning extended api templates
|
14
|
+
|
15
|
+
=== 0.3.0 2011-02-22
|
2
16
|
|
3
17
|
* Added bundler support
|
4
18
|
|
data/README.rdoc
CHANGED
@@ -1,27 +1,133 @@
|
|
1
1
|
module ActsAsApi
|
2
|
-
#
|
2
|
+
# Represents an api template for a model.
|
3
|
+
# This class should not be initiated by yourself, api templates
|
4
|
+
# are created by defining them in the model by calling: +api_accessible+.
|
5
|
+
#
|
6
|
+
# The api template is configured in the block passed to +api_accessible+.
|
7
|
+
#
|
8
|
+
# Please note that +ApiTemplate+ inherits from +Hash+ so you can use all
|
9
|
+
# kind of +Hash+ and +Enumerable+ methods to manipulate the template.
|
3
10
|
class ApiTemplate < Hash
|
4
11
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
12
|
+
# The name of the api template as a Symbol.
|
13
|
+
attr_accessor :api_template
|
14
|
+
|
15
|
+
# Returns a new ApiTemplate with the api template name
|
16
|
+
# set to the passed template.
|
17
|
+
def self.create(template)
|
18
|
+
t = ApiTemplate.new
|
19
|
+
t.api_template = template
|
20
|
+
return t
|
11
21
|
end
|
12
22
|
|
23
|
+
# Adds an item to the api template
|
24
|
+
#
|
25
|
+
# The value passed can be one of the following:
|
26
|
+
# * Symbol - the method with the same name will be called on the model when rendering.
|
27
|
+
# * String - must be in the form "method1.method2.method3", will call this method chain.
|
28
|
+
# * Hash - will be added as a sub hash and all its items will be resolved the way described above.
|
29
|
+
#
|
30
|
+
# Possible options to pass:
|
31
|
+
# * :template - Determine the template that should be used to render the item if it is
|
32
|
+
# +api_accessible+ itself.
|
13
33
|
def add(val, options = {})
|
14
34
|
item_key = (options[:as] || val).to_sym
|
15
|
-
|
35
|
+
|
16
36
|
self[item_key] = val
|
17
|
-
|
37
|
+
|
18
38
|
@options ||= {}
|
19
39
|
@options[item_key] = options
|
20
40
|
end
|
21
41
|
|
22
|
-
|
23
|
-
|
42
|
+
# Removes an item from the template
|
43
|
+
def remove(item)
|
44
|
+
self.delete(item)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns the options of an item in the api template
|
48
|
+
def options_for(item)
|
49
|
+
@options[item]
|
24
50
|
end
|
25
51
|
|
52
|
+
# Returns the passed option of an item in the api template
|
53
|
+
def option_for(item, option)
|
54
|
+
@options[item][option] if @options[item]
|
55
|
+
end
|
56
|
+
|
57
|
+
# If a special template name for the passed item is specified
|
58
|
+
# it will be returned, if not the original api template.
|
59
|
+
def api_template_for(parent, item)
|
60
|
+
return api_template unless parent.is_a? ActsAsApi::ApiTemplate
|
61
|
+
parent.option_for(item, :template) || api_template
|
62
|
+
end
|
63
|
+
|
64
|
+
# Decides if the passed item should be added to
|
65
|
+
# the response.
|
66
|
+
def allowed_to_render?(parent, item, model)
|
67
|
+
return true unless parent.is_a? ActsAsApi::ApiTemplate
|
68
|
+
allowed = true
|
69
|
+
allowed = condition_fulfilled?(model, parent.option_for(item, :if)) if parent.option_for(item, :if)
|
70
|
+
allowed = !(condition_fulfilled?(model, parent.option_for(item, :unless))) if parent.option_for(item, :unless)
|
71
|
+
return allowed
|
72
|
+
end
|
73
|
+
|
74
|
+
def condition_fulfilled?(model, condition)
|
75
|
+
case condition
|
76
|
+
when Symbol
|
77
|
+
result = model.send(condition)
|
78
|
+
when Proc
|
79
|
+
result = condition.call(model)
|
80
|
+
end
|
81
|
+
!result.nil? && !result.is_a?(FalseClass)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Generates a hash that represents the api response based on this
|
85
|
+
# template for the passed model instance.
|
86
|
+
def to_response_hash(model)
|
87
|
+
queue = []
|
88
|
+
api_output = {}
|
89
|
+
queue << { :parent => api_output, :item => self }
|
90
|
+
|
91
|
+
until queue.empty? do
|
92
|
+
leaf = queue.pop
|
93
|
+
|
94
|
+
leaf[:item].each do |k,v|
|
95
|
+
|
96
|
+
next unless allowed_to_render?(leaf[:item], k, model)
|
97
|
+
|
98
|
+
case v
|
99
|
+
when Symbol
|
100
|
+
if model.respond_to?(v)
|
101
|
+
out = model.send v
|
102
|
+
end
|
103
|
+
|
104
|
+
when Proc
|
105
|
+
out = v.call(model)
|
106
|
+
|
107
|
+
when String
|
108
|
+
# go up the call chain
|
109
|
+
out = model
|
110
|
+
v.split(".").each do |method|
|
111
|
+
out = out.send(method.to_sym)
|
112
|
+
end
|
113
|
+
|
114
|
+
when Hash
|
115
|
+
leaf[:parent][k] ||= {}
|
116
|
+
queue << { :parent => leaf[:parent][k], :item => v}
|
117
|
+
next
|
118
|
+
end
|
119
|
+
|
120
|
+
if out.respond_to?(:as_api_response)
|
121
|
+
sub_template = api_template_for(leaf[:item], k)
|
122
|
+
out = out.send(:as_api_response, sub_template)
|
123
|
+
end
|
124
|
+
|
125
|
+
leaf[:parent][k] = out
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
api_output
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
26
133
|
end
|
27
|
-
end
|
data/lib/acts_as_api/array.rb
CHANGED
data/lib/acts_as_api/base.rb
CHANGED
@@ -32,15 +32,9 @@ module ActsAsApi
|
|
32
32
|
# *Note*: There is only whitelisting for api accessible attributes.
|
33
33
|
# So once the model acts as api, you have to determine all attributes here that should
|
34
34
|
# be contained in the api responses.
|
35
|
-
def api_accessible_deprecated(api_templates)
|
36
|
-
api_templates.each do |api_template, attributes|
|
37
|
-
write_inheritable_attribute("api_accessible_#{api_template}".to_sym, Set.new(attributes) + (api_accessible_attributes(api_template) || []))
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
35
|
def api_accessible(api_template, options = {}, &block)
|
42
36
|
|
43
|
-
attributes = api_accessible_attributes(api_template) || ApiTemplate.
|
37
|
+
attributes = api_accessible_attributes(api_template) || ApiTemplate.create(api_template)
|
44
38
|
|
45
39
|
attributes.merge!(api_accessible_attributes(options[:extend])) if options[:extend]
|
46
40
|
|
@@ -55,75 +49,22 @@ module ActsAsApi
|
|
55
49
|
def api_accessible_attributes(api_template)
|
56
50
|
read_inheritable_attribute("api_accessible_#{api_template}".to_sym)
|
57
51
|
end
|
58
|
-
|
59
52
|
end
|
60
53
|
|
61
54
|
module InstanceMethods
|
62
55
|
|
63
56
|
# Creates the api response of the model and returns it as a Hash.
|
57
|
+
# Will raise an exception if the passed api template is not defined for the model
|
64
58
|
def as_api_response(api_template)
|
65
59
|
api_attributes = self.class.api_accessible_attributes(api_template)
|
66
|
-
|
60
|
+
|
67
61
|
raise "acts_as_api template :#{api_template.to_s} was not found for model #{self.class}" if api_attributes.nil?
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
return api_output if api_attributes.nil?
|
72
|
-
|
73
|
-
queue = []
|
74
|
-
queue << { :parent => api_output, :item => api_attributes}
|
75
|
-
|
76
|
-
until queue.empty? do
|
77
|
-
|
78
|
-
leaf = queue.pop
|
79
|
-
|
80
|
-
leaf[:item].each do |k,v|
|
81
|
-
|
82
|
-
if leaf[:item].respond_to?(:option_for)
|
83
|
-
sub_template = leaf[:item].option_for(k, :template) || api_template
|
84
|
-
else
|
85
|
-
sub_template = api_template
|
86
|
-
end
|
87
|
-
|
88
|
-
case v
|
89
|
-
when Symbol
|
90
|
-
|
91
|
-
if self.respond_to?(v)
|
92
|
-
out = send v
|
93
|
-
end
|
94
|
-
|
95
|
-
when Proc
|
96
|
-
out = v.call(self)
|
97
|
-
|
98
|
-
when String
|
99
|
-
# go up the call chain
|
100
|
-
out = self
|
101
|
-
v.split(".").each do |method|
|
102
|
-
out = out.send(method.to_sym)
|
103
|
-
end
|
104
|
-
|
105
|
-
when Hash
|
106
|
-
leaf[:parent][k] ||= {}
|
107
|
-
queue << { :parent => leaf[:parent][k], :item => v}
|
108
|
-
next
|
109
|
-
end
|
110
|
-
|
111
|
-
if out.respond_to?(:as_api_response)
|
112
|
-
out = out.send(:as_api_response, sub_template)
|
113
|
-
end
|
114
|
-
|
115
|
-
leaf[:parent][k] = out
|
116
|
-
|
117
|
-
end
|
118
|
-
|
119
|
-
end
|
120
|
-
|
121
|
-
api_output
|
122
|
-
|
123
|
-
end
|
124
|
-
|
62
|
+
|
63
|
+
api_attributes.to_response_hash(self)
|
125
64
|
end
|
126
65
|
|
127
66
|
end
|
128
|
-
|
67
|
+
|
129
68
|
end
|
69
|
+
|
70
|
+
end
|
data/lib/acts_as_api/config.rb
CHANGED
@@ -23,8 +23,12 @@ module ActsAsApi
|
|
23
23
|
# automatically
|
24
24
|
attr_accessor_with_default :default_root, :record
|
25
25
|
|
26
|
+
# If true a json response will be automatically wrapped into
|
27
|
+
# a JavaScript function call in case a :callback param is passed.
|
26
28
|
attr_accessor_with_default :allow_jsonp_callback, false
|
27
29
|
|
30
|
+
# If true the jsonp function call will get the http status passed
|
31
|
+
# as a second parameter
|
28
32
|
attr_accessor_with_default :add_http_status_to_jsonp_response, true
|
29
33
|
|
30
34
|
end
|
data/lib/acts_as_api/version.rb
CHANGED
data/lib/acts_as_api.rb
CHANGED
@@ -1,12 +1,11 @@
|
|
1
|
-
require 'set'
|
2
1
|
require 'active_model'
|
3
2
|
require 'active_support/core_ext/class'
|
4
3
|
|
5
4
|
$:.unshift(File.dirname(__FILE__)) unless
|
6
5
|
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
7
6
|
|
8
|
-
|
9
|
-
|
7
|
+
require "acts_as_api/array"
|
8
|
+
require "acts_as_api/rails_renderer"
|
10
9
|
|
11
10
|
# acts_as_api is a gem that aims to make the construction of JSON and XML
|
12
11
|
# responses in rails 3 easy and fun.
|
@@ -67,7 +67,7 @@ describe UsersController, :orm => :active_record do
|
|
67
67
|
get :index, :format => 'json', :api_template => :name_only
|
68
68
|
end
|
69
69
|
|
70
|
-
it "should have a root node named users" do
|
70
|
+
it "should have a root node named users" do
|
71
71
|
response_body_json.should have_key("users")
|
72
72
|
end
|
73
73
|
|
@@ -93,7 +93,7 @@ describe UsersController, :orm => :active_record do
|
|
93
93
|
get :show, :format => 'json', :api_template => :name_only, :id => @luke.id
|
94
94
|
end
|
95
95
|
|
96
|
-
it "should have a root node named user" do
|
96
|
+
it "should have a root node named user" do
|
97
97
|
response_body_json.should have_key("user")
|
98
98
|
end
|
99
99
|
|
@@ -163,7 +163,7 @@ describe UsersController, :orm => :active_record do
|
|
163
163
|
get :index, :format => 'json', :api_template => :name_only, :callback => @callback
|
164
164
|
end
|
165
165
|
|
166
|
-
it "should wrap the response in the callback" do
|
166
|
+
it "should wrap the response in the callback" do
|
167
167
|
response_body_jsonp(@callback).should_not be_nil
|
168
168
|
end
|
169
169
|
|
@@ -175,7 +175,7 @@ describe UsersController, :orm => :active_record do
|
|
175
175
|
get :show, :format => 'json', :api_template => :name_only, :id => @luke.id, :callback => @callback
|
176
176
|
end
|
177
177
|
|
178
|
-
it "should wrap the response in the callback" do
|
178
|
+
it "should wrap the response in the callback" do
|
179
179
|
response_body_jsonp(@callback).should_not be_nil
|
180
180
|
end
|
181
181
|
|
@@ -184,5 +184,4 @@ describe UsersController, :orm => :active_record do
|
|
184
184
|
end
|
185
185
|
end
|
186
186
|
|
187
|
-
|
188
187
|
end
|
@@ -0,0 +1,284 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper.rb'
|
2
|
+
|
3
|
+
describe ActsAsApi::Base do
|
4
|
+
|
5
|
+
describe "including an association in the api template", :orm => :active_record do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
setup_models
|
9
|
+
end
|
10
|
+
|
11
|
+
after(:each) do
|
12
|
+
clean_up
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "which doesn't acts_as_api" do
|
16
|
+
|
17
|
+
before(:each) do
|
18
|
+
@response = @luke.as_api_response(:include_tasks)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "returns a hash" do
|
22
|
+
@response.should be_kind_of(Hash)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "returns the correct number of fields" do
|
26
|
+
@response.should have(1).key
|
27
|
+
end
|
28
|
+
|
29
|
+
it "returns all specified fields" do
|
30
|
+
@response.keys.should include(:tasks)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "returns the correct values for the specified fields" do
|
34
|
+
@response[:tasks].should be_an Array
|
35
|
+
@response[:tasks].should have(3).tasks
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should contain the associated sub models" do
|
39
|
+
@response[:tasks].should include(@destroy_deathstar, @study_with_yoda, @win_rebellion)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "which does acts_as_api" do
|
44
|
+
|
45
|
+
context "has_many" do
|
46
|
+
|
47
|
+
before(:each) do
|
48
|
+
Task.acts_as_api
|
49
|
+
Task.api_accessible :include_tasks do |t|
|
50
|
+
t.add :heading
|
51
|
+
t.add :done
|
52
|
+
end
|
53
|
+
@response = @luke.as_api_response(:include_tasks)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "returns a hash" do
|
57
|
+
@response.should be_kind_of(Hash)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "returns the correct number of fields" do
|
61
|
+
@response.should have(1).key
|
62
|
+
end
|
63
|
+
|
64
|
+
it "returns all specified fields" do
|
65
|
+
@response.keys.should include(:tasks)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "returns the correct values for the specified fields" do
|
69
|
+
@response[:tasks].should be_an Array
|
70
|
+
@response[:tasks].should have(3).tasks
|
71
|
+
end
|
72
|
+
|
73
|
+
it "contains the associated child models with the determined api template" do
|
74
|
+
@response[:tasks].each do |task|
|
75
|
+
task.keys.should include(:heading, :done)
|
76
|
+
task.keys.should have(2).attributes
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
it "contains the correct data of the child models" do
|
81
|
+
task_hash = [ @destroy_deathstar, @study_with_yoda, @win_rebellion ].collect{|t| { :done => t.done, :heading => t.heading } }
|
82
|
+
@response[:tasks].should eql task_hash
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context "has_one" do
|
87
|
+
|
88
|
+
before(:each) do
|
89
|
+
Profile.acts_as_api
|
90
|
+
Profile.api_accessible :include_profile do |t|
|
91
|
+
t.add :avatar
|
92
|
+
t.add :homepage
|
93
|
+
end
|
94
|
+
@response = @luke.as_api_response(:include_profile)
|
95
|
+
end
|
96
|
+
|
97
|
+
it "returns a hash" do
|
98
|
+
@response.should be_kind_of(Hash)
|
99
|
+
end
|
100
|
+
|
101
|
+
it "returns the correct number of fields" do
|
102
|
+
@response.should have(1).key
|
103
|
+
end
|
104
|
+
|
105
|
+
it "returns all specified fields" do
|
106
|
+
@response.keys.should include(:profile)
|
107
|
+
end
|
108
|
+
|
109
|
+
it "returns the correct values for the specified fields" do
|
110
|
+
@response[:profile].should be_a Hash
|
111
|
+
@response[:profile].should have(2).attributes
|
112
|
+
end
|
113
|
+
|
114
|
+
it "contains the associated child models with the determined api template" do
|
115
|
+
@response[:profile].keys.should include(:avatar, :homepage)
|
116
|
+
end
|
117
|
+
|
118
|
+
it "contains the correct data of the child models" do
|
119
|
+
profile_hash = { :avatar => @luke.profile.avatar, :homepage => @luke.profile.homepage }
|
120
|
+
@response[:profile].should eql profile_hash
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe "which does acts_as_api, but with using another template name" do
|
127
|
+
|
128
|
+
before(:each) do
|
129
|
+
Task.acts_as_api
|
130
|
+
Task.api_accessible :other_template do |t|
|
131
|
+
t.add :description
|
132
|
+
t.add :time_spent
|
133
|
+
end
|
134
|
+
@response = @luke.as_api_response(:other_sub_template)
|
135
|
+
end
|
136
|
+
|
137
|
+
it "returns a hash" do
|
138
|
+
@response.should be_kind_of(Hash)
|
139
|
+
end
|
140
|
+
|
141
|
+
it "returns the correct number of fields" do
|
142
|
+
@response.should have(2).keys
|
143
|
+
end
|
144
|
+
|
145
|
+
it "returns all specified fields" do
|
146
|
+
@response.keys.should include(:first_name)
|
147
|
+
end
|
148
|
+
|
149
|
+
it "returns the correct values for the specified fields" do
|
150
|
+
@response.values.should include(@luke.first_name)
|
151
|
+
end
|
152
|
+
|
153
|
+
it "returns all specified fields" do
|
154
|
+
@response.keys.should include(:tasks)
|
155
|
+
end
|
156
|
+
|
157
|
+
it "returns the correct values for the specified fields" do
|
158
|
+
@response[:tasks].should be_an Array
|
159
|
+
@response[:tasks].should have(3).tasks
|
160
|
+
end
|
161
|
+
|
162
|
+
it "contains the associated child models with the determined api template" do
|
163
|
+
@response[:tasks].each do |task|
|
164
|
+
task.keys.should include(:description, :time_spent)
|
165
|
+
task.keys.should have(2).attributes
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
it "contains the correct data of the child models" do
|
170
|
+
task_hash = [ @destroy_deathstar, @study_with_yoda, @win_rebellion ].collect{|t| { :description => t.description, :time_spent => t.time_spent } }
|
171
|
+
@response[:tasks].should eql task_hash
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
describe "that is scoped" do
|
176
|
+
|
177
|
+
before(:each) do
|
178
|
+
# extend task model with scope
|
179
|
+
class Task < ActiveRecord::Base
|
180
|
+
scope :completed, where(:done => true)
|
181
|
+
end
|
182
|
+
Task.acts_as_api
|
183
|
+
Task.api_accessible :include_completed_tasks do |t|
|
184
|
+
t.add :heading
|
185
|
+
t.add :done
|
186
|
+
end
|
187
|
+
|
188
|
+
@response = @luke.as_api_response(:include_completed_tasks)
|
189
|
+
end
|
190
|
+
|
191
|
+
it "returns a hash" do
|
192
|
+
@response.should be_kind_of(Hash)
|
193
|
+
end
|
194
|
+
|
195
|
+
it "returns the correct number of fields" do
|
196
|
+
@response.should have(1).key
|
197
|
+
end
|
198
|
+
|
199
|
+
it "returns all specified fields" do
|
200
|
+
@response.keys.should include(:completed_tasks)
|
201
|
+
end
|
202
|
+
|
203
|
+
it "returns the correct values for the specified fields" do
|
204
|
+
@response[:completed_tasks].should be_an Array
|
205
|
+
@response[:completed_tasks].should have(2).tasks
|
206
|
+
end
|
207
|
+
|
208
|
+
it "contains the associated child models with the determined api template" do
|
209
|
+
@response[:completed_tasks].each do |task|
|
210
|
+
task.keys.should include(:heading, :done)
|
211
|
+
task.keys.should have(2).attributes
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
it "contains the correct data of the child models" do
|
216
|
+
task_hash = [ @destroy_deathstar, @study_with_yoda ].collect{|t| { :done => t.done, :heading => t.heading } }
|
217
|
+
@response[:completed_tasks].should eql task_hash
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
describe "handling nil values" do
|
222
|
+
|
223
|
+
context "has_many" do
|
224
|
+
|
225
|
+
before(:each) do
|
226
|
+
Task.acts_as_api
|
227
|
+
Task.api_accessible :include_tasks do |t|
|
228
|
+
t.add :heading
|
229
|
+
t.add :done
|
230
|
+
end
|
231
|
+
@response = @han.as_api_response(:include_tasks)
|
232
|
+
end
|
233
|
+
|
234
|
+
it "returns a hash" do
|
235
|
+
@response.should be_kind_of(Hash)
|
236
|
+
end
|
237
|
+
|
238
|
+
it "returns the correct number of fields" do
|
239
|
+
@response.should have(1).key
|
240
|
+
end
|
241
|
+
|
242
|
+
it "returns all specified fields" do
|
243
|
+
@response.keys.should include(:tasks)
|
244
|
+
end
|
245
|
+
|
246
|
+
it "returns the correct values for the specified fields" do
|
247
|
+
@response[:tasks].should be_kind_of(Array)
|
248
|
+
end
|
249
|
+
|
250
|
+
it "contains no associated child models" do
|
251
|
+
@response[:tasks].should have(0).items
|
252
|
+
end
|
253
|
+
|
254
|
+
end
|
255
|
+
|
256
|
+
context "has one" do
|
257
|
+
before(:each) do
|
258
|
+
Profile.acts_as_api
|
259
|
+
Profile.api_accessible :include_profile do |t|
|
260
|
+
t.add :avatar
|
261
|
+
t.add :homepage
|
262
|
+
end
|
263
|
+
@response = @han.as_api_response(:include_profile)
|
264
|
+
end
|
265
|
+
|
266
|
+
it "returns a hash" do
|
267
|
+
@response.should be_kind_of(Hash)
|
268
|
+
end
|
269
|
+
|
270
|
+
it "returns the correct number of fields" do
|
271
|
+
@response.should have(1).key
|
272
|
+
end
|
273
|
+
|
274
|
+
it "returns all specified fields" do
|
275
|
+
@response.keys.should include(:profile)
|
276
|
+
end
|
277
|
+
|
278
|
+
it "returns nil for the association" do
|
279
|
+
@response[:profile].should be_nil
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|