intermodal 0.0.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/Gemfile +4 -0
- data/LICENSE +1 -1
- data/README +6 -4
- data/Rakefile +6 -0
- data/intermodal.gemspec +51 -0
- data/lib/generators/intermodal_generator.rb +8 -0
- data/lib/intermodal.rb +122 -0
- data/lib/intermodal/api.rb +246 -0
- data/lib/intermodal/api/configuration.rb +40 -0
- data/lib/intermodal/api/railties.rb +21 -0
- data/lib/intermodal/concerns/acceptors/named_resource.rb +12 -0
- data/lib/intermodal/concerns/acceptors/resource.rb +12 -0
- data/lib/intermodal/concerns/controllers/accountability.rb +17 -0
- data/lib/intermodal/concerns/controllers/anonymous.rb +24 -0
- data/lib/intermodal/concerns/controllers/authenticatable.rb +24 -0
- data/lib/intermodal/concerns/controllers/paginated_collection.rb +25 -0
- data/lib/intermodal/concerns/controllers/presentation.rb +17 -0
- data/lib/intermodal/concerns/controllers/resource.rb +51 -0
- data/lib/intermodal/concerns/controllers/resource_linking.rb +58 -0
- data/lib/intermodal/concerns/let.rb +21 -0
- data/lib/intermodal/concerns/models/access_credential.rb +28 -0
- data/lib/intermodal/concerns/models/account.rb +16 -0
- data/lib/intermodal/concerns/models/accountability.rb +47 -0
- data/lib/intermodal/concerns/models/db_access_token.rb +29 -0
- data/lib/intermodal/concerns/models/has_parent_resource.rb +45 -0
- data/lib/intermodal/concerns/models/presentation.rb +25 -0
- data/lib/intermodal/concerns/models/redis_access_token.rb +60 -0
- data/lib/intermodal/concerns/models/resource_linking.rb +126 -0
- data/lib/intermodal/concerns/models/sanitize_html.rb +35 -0
- data/lib/intermodal/concerns/presenters/named_resource.rb +12 -0
- data/lib/intermodal/concerns/presenters/resource.rb +14 -0
- data/lib/intermodal/concerns/rails/rails_3_stack.rb +42 -0
- data/lib/intermodal/concerns/rails/rails_4_stack.rb +17 -0
- data/lib/intermodal/concerns/rails/use_warden.rb +21 -0
- data/lib/intermodal/config.rb +15 -0
- data/lib/intermodal/configuration.rb +11 -0
- data/lib/intermodal/controllers/api_controller.rb +26 -0
- data/lib/intermodal/controllers/linking_resource_controller.rb +8 -0
- data/lib/intermodal/controllers/nested_resource_controller.rb +18 -0
- data/lib/intermodal/controllers/resource_controller.rb +11 -0
- data/lib/intermodal/dsl/controllers.rb +125 -0
- data/lib/intermodal/dsl/mapping.rb +79 -0
- data/lib/intermodal/dsl/presentation_helpers.rb +107 -0
- data/lib/intermodal/mapping/acceptor.rb +2 -2
- data/lib/intermodal/mapping/mapper.rb +39 -13
- data/lib/intermodal/mapping/presenter.rb +12 -6
- data/lib/intermodal/proxies/linking_resources.rb +58 -0
- data/lib/intermodal/proxies/will_paginate.rb +85 -0
- data/lib/intermodal/rack/auth.rb +29 -0
- data/lib/intermodal/rack/dummy_store.rb +24 -0
- data/lib/intermodal/rack/rescue.rb +82 -0
- data/lib/intermodal/responders/linking_resource_responder.rb +21 -0
- data/lib/intermodal/responders/resource_responder.rb +64 -0
- data/lib/intermodal/rspec/acceptors.rb +79 -0
- data/lib/intermodal/rspec/models/accountability.rb +114 -0
- data/lib/intermodal/rspec/models/has_parent_resource.rb +132 -0
- data/lib/intermodal/rspec/models/resource_linking.rb +234 -0
- data/lib/intermodal/rspec/models/sanitization.rb +84 -0
- data/lib/intermodal/rspec/presenters.rb +92 -0
- data/lib/intermodal/rspec/requests/authenticated_requests.rb +17 -0
- data/lib/intermodal/rspec/requests/linked_resources.rb +180 -0
- data/lib/intermodal/rspec/requests/paginated_collection.rb +60 -0
- data/lib/intermodal/rspec/requests/rack.rb +142 -0
- data/lib/intermodal/rspec/requests/request_validations.rb +36 -0
- data/lib/intermodal/rspec/requests/resources.rb +275 -0
- data/lib/intermodal/rspec/requests/rfc2616_status_codes.rb +51 -0
- data/lib/intermodal/rspec/validators.rb +86 -0
- data/lib/intermodal/validators/account_validator.rb +27 -0
- data/lib/intermodal/validators/different_account_validator.rb +27 -0
- data/lib/intermodal/version.rb +3 -0
- data/spec/mapping/acceptors_spec.rb +142 -0
- data/spec/mapping/presenters_spec.rb +186 -0
- data/spec/models/accountability_spec.rb +13 -0
- data/spec/models/has_parent_resource_spec.rb +18 -0
- data/spec/models/resource_linking_spec.rb +21 -0
- data/spec/proxies/will_paginate_spec.rb +163 -0
- data/spec/rack/auth_spec.rb +51 -0
- data/spec/requests/linked_resources.rb +37 -0
- data/spec/requests/nested_resources_spec.rb +54 -0
- data/spec/requests/resources_spec.rb +50 -0
- data/spec/spec_helper.rb +53 -0
- data/spec/support/api.rb +50 -0
- data/spec/support/app/class_builder.rb +41 -0
- data/spec/support/app/db/adapter_helper.rb +53 -0
- data/spec/support/app/db/authentication_schema_helper.rb +62 -0
- data/spec/support/app/db/migration_helper.rb +44 -0
- data/spec/support/app/schema.rb +101 -0
- data/spec/support/application.rb +23 -0
- data/spec/support/blueprints.rb +41 -0
- data/spec/support/epiphyte.rb +29 -0
- metadata +393 -52
- data/lib/intermodal/base.rb +0 -13
- data/lib/intermodal/declare_controllers.rb +0 -102
- data/lib/intermodal/mapping.rb +0 -4
- data/lib/intermodal/mapping/dsl.rb +0 -76
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'active_model/validator'
|
2
|
+
|
3
|
+
module Intermodal
|
4
|
+
module Validators
|
5
|
+
# Validates the associated resource is owned by the same account
|
6
|
+
# Examples:
|
7
|
+
#
|
8
|
+
# validates parent_id, account: true
|
9
|
+
# validates parent_id, account: { through: association }
|
10
|
+
#
|
11
|
+
class AccountValidator < ActiveModel::EachValidator
|
12
|
+
def validate_each(record, attribute, value)
|
13
|
+
return if value.nil?
|
14
|
+
association_name = options[:through] || attribute.to_s.gsub(/_id/, '')
|
15
|
+
return if record.send(association_name).account_id == record.account_id
|
16
|
+
record.errors[attribute] << message
|
17
|
+
end
|
18
|
+
|
19
|
+
def message
|
20
|
+
options[:message] || 'must belong to the same account'
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
AccountValidator = Intermodal::Validators::AccountValidator unless defined? AccountValidator
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'active_model/validator'
|
2
|
+
|
3
|
+
module Intermodal
|
4
|
+
module Validators
|
5
|
+
# Validates the associated resource is owned by a different account
|
6
|
+
# Examples:
|
7
|
+
#
|
8
|
+
# validates parent_id, different_account: true
|
9
|
+
# validates parent_id, different_account: { through: association }
|
10
|
+
#
|
11
|
+
class DifferentAccountValidator < ActiveModel::EachValidator
|
12
|
+
def validate_each(record, attribute, value)
|
13
|
+
return if value.nil?
|
14
|
+
association_name = options[:through] || attribute.to_s.gsub(/_id/, '')
|
15
|
+
return if record.send(association_name).account_id != record.account_id
|
16
|
+
record.errors[attribute] << message
|
17
|
+
end
|
18
|
+
|
19
|
+
def message
|
20
|
+
options[:message] || 'must belong to a different account'
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
DifferentAccountValidator = Intermodal::Validators::DifferentAccountValidator unless defined? DifferentAccountValidator
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Intermodal::Mapping::Acceptor do
|
4
|
+
include SpecHelpers::ClassBuilder
|
5
|
+
|
6
|
+
describe '.call' do
|
7
|
+
subject { acceptor.call(params) }
|
8
|
+
|
9
|
+
context 'with pass-through mappings' do
|
10
|
+
let(:acceptor) do
|
11
|
+
define_class :TestAcceptor, Intermodal::Mapping::Acceptor do
|
12
|
+
accepts :acceptable_field
|
13
|
+
accepts :optional_field
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:value) { 'Accepted Field' }
|
18
|
+
let(:params) { { :acceptable_field => value, :unacceptable_field => true } }
|
19
|
+
|
20
|
+
it 'should accept explicitly whitelisted fields' do
|
21
|
+
should include(:acceptable_field)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should pass through value without transformation' do
|
25
|
+
subject[:acceptable_field].should eql(value)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should not accept undeclared fields' do
|
29
|
+
should_not include(:unacceptable_field)
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'without optional field in params' do
|
33
|
+
# Since we pass the output of an acceptor directly into
|
34
|
+
# the active record #create or #update_attributes, we want
|
35
|
+
# the hash to look like:
|
36
|
+
#
|
37
|
+
# { :acceptable_fields => 'Something' }
|
38
|
+
#
|
39
|
+
# rather than
|
40
|
+
#
|
41
|
+
# { :acceptable_field => 'Something', :optional_field => nil }
|
42
|
+
#
|
43
|
+
# Doing so will update the resource and null out the fields that
|
44
|
+
# have not been passed through params.
|
45
|
+
it 'should not include the optional field' do
|
46
|
+
should_not include(:optional_field)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'with optional field in params' do
|
51
|
+
let(:params) { { :acceptable_field => value, :optional_field => value } }
|
52
|
+
|
53
|
+
it 'should include the optional field' do
|
54
|
+
should include(:optional_field)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should pass through value without transformation' do
|
58
|
+
subject[:optional_field].should eql(value)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'with pass-through alias mappings' do
|
64
|
+
let(:acceptor) do
|
65
|
+
define_class :TestAcceptor, Intermodal::Mapping::Acceptor do
|
66
|
+
accepts :name, :with => :full_name
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
let(:value) { 'Henry Deacon' }
|
71
|
+
let(:params) { { :full_name => value } }
|
72
|
+
|
73
|
+
it 'should present explicitly whitelisted fields' do
|
74
|
+
should include(:name)
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should pass through value without transformation' do
|
78
|
+
subject[:name].should eql(params[:full_name])
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'should not present undeclared fields' do
|
82
|
+
should_not include(:full_name)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'with nested mappings' do
|
87
|
+
let(:acceptor) do
|
88
|
+
define_class :TestAcceptor, Intermodal::Mapping::Acceptor do
|
89
|
+
# Use this to create nested parameters from flattened parameters
|
90
|
+
accepts :name, :with => [ :first_name, :last_name ]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
let(:first_name) { 'Henry' }
|
95
|
+
let(:last_name) { 'Deacon' }
|
96
|
+
let(:params) { { :first_name => first_name, :last_name => last_name } }
|
97
|
+
|
98
|
+
it 'should merge fields into a single hash of fields' do
|
99
|
+
should include(:name)
|
100
|
+
subject[:name].should include(:first_name)
|
101
|
+
subject[:name].should include(:last_name)
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'should merge fields without transforming its value' do
|
105
|
+
subject[:name][:first_name].should eql(first_name)
|
106
|
+
subject[:name][:last_name].should eql(last_name)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Unless you've explicitly declared the merged fields, it should
|
110
|
+
# not include it.
|
111
|
+
it 'should not accept merged fields' do
|
112
|
+
should_not include(:first_name)
|
113
|
+
should_not include(:last_name)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context 'with arbitrary mappings' do
|
118
|
+
let(:acceptor) do
|
119
|
+
define_class :TestAcceptor, Intermodal::Mapping::Acceptor do
|
120
|
+
# This lets you use aribrary functions to map out accepted fields.
|
121
|
+
# Beware! For many use-cases, declaring these in the model works better.
|
122
|
+
# Beware! Do not use functions with side-effects
|
123
|
+
accepts :phone_number, :with => lambda { |o| o[:phone_number].gsub(/[^0-9]/, '') }
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
let(:value) { '555-555-5555' }
|
128
|
+
let(:params) { { :phone_number => value } }
|
129
|
+
|
130
|
+
it 'should accept an arbitrary mapping' do
|
131
|
+
should include(:phone_number)
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'should transform the value' do
|
135
|
+
subject[:phone_number].should_not eql(value)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
pending 'with scoped acceptor'
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
@@ -0,0 +1,186 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Intermodal::Mapping::Presenter do
|
4
|
+
include SpecHelpers::ClassBuilder
|
5
|
+
include SpecHelpers::Application
|
6
|
+
|
7
|
+
describe '.call' do
|
8
|
+
subject { presenter.call(resource) }
|
9
|
+
let(:resource) { item }
|
10
|
+
|
11
|
+
context 'with pass-through mappings' do
|
12
|
+
let(:presenter) do
|
13
|
+
define_class :TestPresenter, Intermodal::Mapping::Presenter do
|
14
|
+
presents :name
|
15
|
+
presents :description
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should present explicitly whitelisted fields' do
|
20
|
+
should include(:name)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should pass through value without transformation' do
|
24
|
+
subject[:name].should eql(resource.name)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should present all declared fields regardless of value' do
|
28
|
+
should include(:description)
|
29
|
+
subject[:description].should be_nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'with pass-through alias mappings' do
|
34
|
+
let(:presenter) do
|
35
|
+
define_class :TestPresenter, Intermodal::Mapping::Presenter do
|
36
|
+
presents :full_name, :with => :name
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should present explicitly whitelisted fields' do
|
41
|
+
should include(:full_name)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should pass through value without transformation' do
|
45
|
+
subject[:full_name].should eql(resource.name)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should not present undeclared fields' do
|
49
|
+
should_not include(:name)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'with nested mappings' do
|
54
|
+
let(:presenter) do
|
55
|
+
define_class :TestPresenter, Intermodal::Mapping::Presenter do
|
56
|
+
|
57
|
+
# Use this to create nested presentation
|
58
|
+
presents :metadata, :with => [ :name, :description ]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
let(:resource) { Item.make(:name => name, :description => description) }
|
63
|
+
let(:name) { 'Weird Eureka Thing' }
|
64
|
+
let(:description) { 'Makes Eureka Go Boom!' }
|
65
|
+
|
66
|
+
it 'should merge fields into a single hash of fields' do
|
67
|
+
should include(:metadata)
|
68
|
+
subject[:metadata].should include(:name)
|
69
|
+
subject[:metadata].should include(:description)
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should merge fields without transforming its value' do
|
73
|
+
subject[:metadata][:name].should eql(name)
|
74
|
+
subject[:metadata][:description].should eql(description)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Unless you've explicitly declared the merged fields, it should
|
78
|
+
# not present it.
|
79
|
+
it 'should not present undeclared fields' do
|
80
|
+
should_not include(:name)
|
81
|
+
should_not include(:description)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
pending 'with always_nest_collection'
|
86
|
+
context 'with arbitrary mappings' do
|
87
|
+
let(:presenter) do
|
88
|
+
define_class :TestPresenter, Intermodal::Mapping::Presenter do
|
89
|
+
# This lets you use aribrary functions to map out accepted fields.
|
90
|
+
# Beware! For many use-cases, declaring these in the model works better.
|
91
|
+
# Beware! Do not use functions with side-effects
|
92
|
+
presents :name, :with => lambda { |o| o[:name].upcase }
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'should accept an arbitrary mapping' do
|
97
|
+
should include(:name)
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'should transform the value' do
|
101
|
+
subject[:name].should_not eql(resource.name)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context 'when scoping' do
|
106
|
+
subject { presenter.call(resource, :scope => scope) }
|
107
|
+
|
108
|
+
context 'without scope declaration' do
|
109
|
+
let(:scope) { :default }
|
110
|
+
let(:presenter) do
|
111
|
+
define_class :TestPresenter, Intermodal::Mapping::Presenter do
|
112
|
+
presents :name
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'should default to :default scope' do
|
117
|
+
should include(:name)
|
118
|
+
subject[:name].should eql(resource.name)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
context 'with mixed scopes' do
|
123
|
+
let(:scope) { :default }
|
124
|
+
let(:presenter) do
|
125
|
+
define_class :TestPresenter, Intermodal::Mapping::Presenter do
|
126
|
+
presents :name
|
127
|
+
presents :description, :scope => :details
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
let(:resource) { Item.make(:name => name, :description => description) }
|
132
|
+
let(:name) { 'Weird Eureka Thing' }
|
133
|
+
let(:description) { 'Makes Eureka Go Boom!' }
|
134
|
+
|
135
|
+
it 'should default to :default scope' do
|
136
|
+
should include(:name)
|
137
|
+
subject[:name].should eql(resource.name)
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'should not present attributes outside of scope' do
|
141
|
+
should_not include(:description)
|
142
|
+
end
|
143
|
+
|
144
|
+
context 'when called with non-default scope' do
|
145
|
+
let(:scope) { :details }
|
146
|
+
|
147
|
+
it 'should include non-overlapping attributes from default scope' do
|
148
|
+
should include(:name)
|
149
|
+
subject[:name].should eql(resource.name)
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'should present attributes from non-default scope' do
|
153
|
+
should include(:description)
|
154
|
+
subject[:description].should eql(resource.description)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
context 'with overlapping scopes' do
|
160
|
+
let(:scope) { :default }
|
161
|
+
let(:presenter) do
|
162
|
+
define_class :TestPresenter, Intermodal::Mapping::Presenter do
|
163
|
+
presents :name
|
164
|
+
presents :name, :with => lambda { |o| 'boo!' }, :scope => :details
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'should default to :default scope' do
|
169
|
+
should include(:name)
|
170
|
+
subject[:name].should eql(resource.name)
|
171
|
+
end
|
172
|
+
|
173
|
+
context 'when called with non-default scope' do
|
174
|
+
let(:scope) { :details }
|
175
|
+
|
176
|
+
it 'should present attributes from non-default scope' do
|
177
|
+
should include(:name)
|
178
|
+
subject[:name].should_not eql(resource.name)
|
179
|
+
subject[:name].should eql('boo!')
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Intermodal::Models::Accountability do
|
4
|
+
context 'when implemented as a resource' do
|
5
|
+
include SpecHelpers::Application
|
6
|
+
include Intermodal::RSpec::Accountability
|
7
|
+
|
8
|
+
subject { item }
|
9
|
+
implements_get_interface
|
10
|
+
|
11
|
+
pending 'should belong to account model'
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Intermodal::Models::HasParentResource do
|
4
|
+
context 'when implemented as a resource' do
|
5
|
+
include SpecHelpers::Application
|
6
|
+
include Intermodal::RSpec::HasParentResource
|
7
|
+
|
8
|
+
subject { part }
|
9
|
+
let(:parent_resource_name) { :item }
|
10
|
+
let(:different_parent) { Item.make!(:account => account) }
|
11
|
+
let(:parent_with_different_account) { Item.make!(:account => different_account) }
|
12
|
+
let(:different_account) { Account.make! }
|
13
|
+
|
14
|
+
implements_get_interface_for_nested_resource
|
15
|
+
|
16
|
+
pending 'should belong to parent model'
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Intermodal::Models::ResourceLinking do
|
4
|
+
context 'when implemented as a resource' do
|
5
|
+
include SpecHelpers::Application
|
6
|
+
include Intermodal::RSpec::ResourceLinking
|
7
|
+
|
8
|
+
subject { sku }
|
9
|
+
|
10
|
+
let(:model) { Sku }
|
11
|
+
let(:skus) { item.vendors << vendors }
|
12
|
+
|
13
|
+
# Protip: sku, item, and vendors can be defined in a global helper, such as SpecHelpers::Application
|
14
|
+
let(:sku) { Sku.create(:item => item, :vendor => vendor) }
|
15
|
+
let(:item) { Item.make!(:account => account) }
|
16
|
+
let(:vendor) { Vendor.make!(:account => account) }
|
17
|
+
let(:vendors) { (1..3).map { Vendor.make!(:account => account) } }
|
18
|
+
|
19
|
+
concerned_with_resource_linking :item, :vendor, :skip_association_examples => true, :skip_validation_examples => true
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Intermodal::Proxies::WillPaginate::Collection do
|
4
|
+
include Intermodal::RSpec::Resources
|
5
|
+
include SpecHelpers::Application
|
6
|
+
include SpecHelpers::API
|
7
|
+
|
8
|
+
let(:api_class) do
|
9
|
+
define_class :Api, Rails::Engine do
|
10
|
+
include Intermodal::API
|
11
|
+
include SpecHelpers::Epiphyte
|
12
|
+
|
13
|
+
map_data do
|
14
|
+
presentation_for :item do
|
15
|
+
presents :id
|
16
|
+
presents :name
|
17
|
+
presents :description
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
controllers do
|
22
|
+
end
|
23
|
+
|
24
|
+
routes.draw do
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#as_json' do
|
30
|
+
before(:each) { api_class.load_presentations! }
|
31
|
+
subject { presented_collection }
|
32
|
+
|
33
|
+
let(:presenter) { api_class.presenters[:item] }
|
34
|
+
let(:collection) { Item.make!(3, :account => account) }
|
35
|
+
let(:paginated_collection) { collection; Item.paginate :page => 1 }
|
36
|
+
let(:presented_collection) { paginated_collection.as_json presenter_options }
|
37
|
+
|
38
|
+
let(:collection_ids) { collection.map(&:id) }
|
39
|
+
|
40
|
+
let(:_ids) { ->(r) { r[:id] } }
|
41
|
+
let(:presented_collection_ids) { presented_collection[:collection].map(&_ids) }
|
42
|
+
|
43
|
+
context 'with presenter default options' do
|
44
|
+
let(:presenter_options) { { :presenter => presenter } }
|
45
|
+
|
46
|
+
it 'should present page' do
|
47
|
+
subject[:page].should_not be_nil
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should present per_page' do
|
51
|
+
subject[:per_page].should_not be_nil
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should present total_pages' do
|
55
|
+
subject[:total_pages].should_not be_nil
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should present total_entries' do
|
59
|
+
subject[:total_entries].should_not be_nil
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should present collection' do
|
63
|
+
subject[:collection].should_not be_nil
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should present collection of resources' do
|
67
|
+
presented_collection_ids.should eql(collection_ids)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'with root option' do
|
72
|
+
let(:presenter_options) { { :presenter => presenter, :root => root } }
|
73
|
+
let(:root) { :node }
|
74
|
+
let(:presented_collection_ids) { presented_collection[root].map(&_ids) }
|
75
|
+
|
76
|
+
it 'should present page' do
|
77
|
+
subject[:page].should_not be_nil
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should present per_page' do
|
81
|
+
subject[:per_page].should_not be_nil
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should present total_pages' do
|
85
|
+
subject[:total_pages].should_not be_nil
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'should present total_entries' do
|
89
|
+
subject[:total_entries].should_not be_nil
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'should present collection' do
|
93
|
+
subject[root].should_not be_nil
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'should present collection of resources' do
|
97
|
+
presented_collection_ids.should eql(collection_ids)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'with always_nest_collections option' do
|
102
|
+
let(:presenter_options) { { :presenter => presenter, :always_nest_collections => true } }
|
103
|
+
let(:presented_collection_ids) { presented_collection[:collection].map(&_ids) }
|
104
|
+
let(:_ids) { ->(r) { r['item'][:id] } }
|
105
|
+
|
106
|
+
it 'should present page' do
|
107
|
+
subject[:page].should_not be_nil
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'should present per_page' do
|
111
|
+
subject[:per_page].should_not be_nil
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'should present total_pages' do
|
115
|
+
subject[:total_pages].should_not be_nil
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'should present total_entries' do
|
119
|
+
subject[:total_entries].should_not be_nil
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'should present collection' do
|
123
|
+
subject[:collection].should_not be_nil
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'should present collection of resources' do
|
127
|
+
presented_collection_ids.should eql(collection_ids)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context 'with always_nest_collections and root option' do
|
132
|
+
let(:presenter_options) { { :presenter => presenter, :root => root, :always_nest_collections => true } }
|
133
|
+
let(:root) { :nodes }
|
134
|
+
let(:element_name) { root.to_s.singularize }
|
135
|
+
let(:presented_collection_ids) { presented_collection[root].map(&_ids) }
|
136
|
+
let(:_ids) { ->(r) { r[element_name][:id] } }
|
137
|
+
|
138
|
+
it 'should present page' do
|
139
|
+
subject[:page].should_not be_nil
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'should present per_page' do
|
143
|
+
subject[:per_page].should_not be_nil
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'should present total_pages' do
|
147
|
+
subject[:total_pages].should_not be_nil
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'should present total_entries' do
|
151
|
+
subject[:total_entries].should_not be_nil
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'should present collection' do
|
155
|
+
subject[root].should_not be_nil
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'should present collection of resources' do
|
159
|
+
presented_collection_ids.should eql(collection_ids)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|