gatherable 1.2.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 828a1fcd67fe3618315e17c81f7cd0906a7733a1
4
- data.tar.gz: 3975e3ecdd2778d48040adc30eda40d5ef26cd7c
3
+ metadata.gz: b4cc971a909ed605b6e2438d967017cb5e8b0197
4
+ data.tar.gz: 3ab989877d63570afb2b91cf194814468c76f263
5
5
  SHA512:
6
- metadata.gz: 61c15dbed0e1e948e6a7996f130163ca4cfbb3ab47b9ffc42dcc43b445e2e54e5919bf2c2073a77f12f5a7fa54fa31049f135183b23887061684af408903e56b
7
- data.tar.gz: df294dd9354f40b269daf81e630ceb11cfce5f9982e3a3e35be159d70d336cabc671597dce1b2fd6e4ce523eeb61e0942e43c00ae4a4d0368811c7b891deb40a
6
+ metadata.gz: ed5f8b4d444fdf3cadc0fee9150f45da62c555b518ce6a2849862bb8ddc5470e49eab0da94383b777f2ab3e614cc2f92c4eb6afc9f41bef7709cb24cef068c97
7
+ data.tar.gz: 0950e67aa43118895f8fbd53f0b64d8bebd1c13fd1c4f964808524392dc01c96f34fec8ac1b693c325c54446a9d1ee855d40d4f0a8cdd2c6322539343276c3c0
@@ -1,20 +1,21 @@
1
1
  module Gatherable
2
2
  class ApplicationController < ::ActionController::Base
3
- before_action :authenticate, only: [:create]
3
+ before_action :set_gatherable_id
4
+ before_action :authenticate
4
5
 
5
6
  def index
6
- render :json => model_class.where(global_identifier => global_identifier), :status => :found
7
+ render :json => model_class.where(global_id => global_id_val), :status => :found
7
8
  end
8
9
 
9
10
  def show
10
- render :json => model_instance, :status => :found
11
+ render :json => model_class.find_by!(global_id => global_id_val, model_id => params[model_id]), :status => :found
11
12
  rescue ActiveRecord::RecordNotFound => e
12
13
  render :json => { :errors => e.message}, :status => :not_found
13
14
  end
14
15
 
15
16
  def create
16
17
  if data_table.new_record_strategy == :update
17
- model = model_class.find_or_initialize_by(global_identifier => model_params[global_identifier])
18
+ model = model_class.find_or_initialize_by(global_id => global_id_val)
18
19
  model.update_attributes(model_params)
19
20
  render :json => model, :status => :ok
20
21
  else
@@ -44,11 +45,12 @@ module Gatherable
44
45
 
45
46
  def authenticate
46
47
  return unless Gatherable.config.auth_method == :session
47
- head :unauthorized unless params[global_identifier] == session[global_identifier]
48
+ return unless requires_global_id_param?
49
+ head :unauthorized unless params[global_id] == session[global_id]
48
50
  end
49
51
 
50
52
  def model_instance
51
- model_class.find_by!(params.slice(model_id, global_identifier))
53
+ model_class.find_by!(params.slice(model_id, global_id_val))
52
54
  end
53
55
 
54
56
  def model_class
@@ -73,16 +75,28 @@ module Gatherable
73
75
 
74
76
  def model_params
75
77
  params.require(model_name_as_var).permit(
76
- *model_class.column_names
77
- ).merge(global_identifier => params[global_identifier])
78
+ *model_class.column_names - [global_id]
79
+ ).merge(global_id => global_id_val)
78
80
  end
79
81
 
80
- def global_identifier
82
+ def global_id
81
83
  Gatherable.config.global_identifier
82
84
  end
83
85
 
84
86
  def data_table
85
87
  DataTable.find_by_name(model_name_as_var)
86
88
  end
89
+
90
+ def set_gatherable_id
91
+ session[global_id] ||= SecureRandom.urlsafe_base64
92
+ end
93
+
94
+ def global_id_val
95
+ requires_global_id_param? ? params[global_id] : session[global_id]
96
+ end
97
+
98
+ def requires_global_id_param?
99
+ Gatherable.config.prefixed_resources.include? data_table.name
100
+ end
87
101
  end
88
102
  end
data/config/routes.rb CHANGED
@@ -1,10 +1,23 @@
1
- Gatherable::Engine.routes.draw do
2
- Gatherable.config.data_tables.each do |data_table|
3
- scope :path => "/:#{Gatherable.config.global_identifier}" do
4
- resources(data_table.name.to_s.pluralize.to_sym,
5
- :only => data_table.allowed_controller_actions.map(&:to_sym),
6
- :param => "#{data_table.name}_id"
7
- )
1
+ class Gatherable::RouteDrawer
2
+ def self.draw
3
+ Gatherable::Engine.routes.draw do
4
+ Gatherable.config.data_tables.each do |data_table|
5
+ if Gatherable.config.prefixed_resources.include? data_table.name
6
+ scope :path => "/:#{Gatherable.config.global_identifier}" do
7
+ resources(data_table.name.to_s.pluralize.to_sym,
8
+ :only => data_table.allowed_controller_actions.map(&:to_sym),
9
+ :param => "#{data_table.name}_id"
10
+ )
11
+ end
12
+ else
13
+ resources(data_table.name.to_s.pluralize.to_sym,
14
+ :only => data_table.allowed_controller_actions.map(&:to_sym),
15
+ :param => "#{data_table.name}_id"
16
+ )
17
+ end
18
+ end
8
19
  end
9
20
  end
10
21
  end
22
+
23
+ Gatherable::RouteDrawer.draw
@@ -21,7 +21,25 @@ module Gatherable
21
21
  end
22
22
 
23
23
  def auth_method
24
- @auth_method
24
+ @auth_method || :session
25
+ end
26
+
27
+ def prefixed_resources
28
+ @prefixed_resources ||= []
29
+ end
30
+
31
+ def prefixed_resources=(resources)
32
+ all_table_names = DataTable.all.keys
33
+ @prefixed_resources = case resources
34
+ when String, Symbol, Array
35
+ Array(resources).map(&:to_sym) && all_table_names
36
+ when Hash
37
+ if resources.key?(:only)
38
+ Array(resources[:only]).map(&:to_sym) && all_table_names
39
+ elsif resources.key?(:except)
40
+ all_table_names - Array(resources[:except]).map(&:to_sym)
41
+ end
42
+ end
25
43
  end
26
44
  end
27
45
  end
@@ -1,3 +1,3 @@
1
1
  module Gatherable
2
- VERSION = "1.2.0"
2
+ VERSION = "2.0.0"
3
3
  end
@@ -1,6 +1,6 @@
1
1
  require 'rails/generators'
2
2
  class GatherableGenerator < Rails::Generators::NamedBase
3
- source_root File.expand_path('../templates', __FILE__)
3
+ source_root File.expand_path('../../../../', __FILE__)
4
4
  def generate
5
5
  send "generate_#{file_name}"
6
6
  end
@@ -8,7 +8,8 @@ class GatherableGenerator < Rails::Generators::NamedBase
8
8
  private
9
9
 
10
10
  def generate_initializer
11
- copy_file "gatherable.rb", "config/initializers/gatherable.rb"
11
+ copy_file "lib/generators/gatherable/templates/gatherable.rb",
12
+ "config/initializers/gatherable.rb"
12
13
  end
13
14
 
14
15
  def generate_migrations
@@ -25,7 +26,8 @@ class GatherableGenerator < Rails::Generators::NamedBase
25
26
  end
26
27
 
27
28
  def generate_controllers
28
- copy_file 'application_controller.rb', 'app/controllers/gatherable/application_controller.rb'
29
+ copy_file 'app/controllers/gatherable/application_controller.rb',
30
+ 'app/controllers/gatherable/application_controller.rb'
29
31
  Gatherable.config.data_tables.each do |data_table|
30
32
  ControllerWriter.new(data_table).write
31
33
  end
@@ -1,15 +1,15 @@
1
1
  Gatherable.configure do |c|
2
2
  c.global_identifier = :gatherable_id
3
3
 
4
- # c.data_point :data_point_name, :data_point_type, options - see README
4
+ # c.data_point :data_point_name, :data_point_type, options - see README
5
5
  c.data_point :price, :decimal
6
6
 
7
- #c.data_table :table_name, { column_name: :column_type, column_name2: :column_type }, options - see README
7
+ # c.data_table :table_name, { column_name: :column_type, column_name2: :column_type }, options - see README
8
8
  c.data_table :requested_loan_amount, { requested_loan_amount: :decimal, total_cost: :decimal, monthly_repayment_amount: :decimal }
9
9
 
10
- # for both data tables and data points, you'll automatically get a primary key 'table_name_id',
11
- # an indexed global identifier, and timestamps
10
+ # for both data tables and data points, you'll automatically get a primary key 'table_name_id',
11
+ # an indexed global identifier, and timestamps
12
12
 
13
- #If want your db schema to be something besides 'gatherable', uncomment the line below
14
- #c.schema_name = 'foo_bar'
13
+ # If want your db schema to be something besides 'gatherable', uncomment the line below
14
+ # c.schema_name = 'foo_bar'
15
15
  end
@@ -1,64 +1,88 @@
1
1
  require 'rails_helper'
2
- describe 'Gatherable::PricesController' do
3
- before(:all) do
4
- @controller = Gatherable::PricesController.new
5
- Gatherable::ApplicationController.skip_before_action :check_controller_action
2
+
3
+ describe 'Gatherable::PricesController', :type => :request do
4
+
5
+ let(:data_table) { Gatherable.config.data_tables.first }
6
+ let(:model_name) { data_table.name }
7
+ let(:model_class) { data_table.classify }
8
+ let(:controller_class) { data_table.controllerify }
9
+ let(:global_id) { 'session_id123' }
10
+ let(:id) { 1 }
11
+
12
+ let(:params_prefix) { prefix.blank? ? { "session_id" => global_id } : {} }
13
+
14
+ let(:index) { get "/gatherable/#{prefix}#{model_name.to_s.pluralize}.json" }
15
+
16
+ let(:show) do
17
+ get "/gatherable/#{prefix}#{model_name.to_s.pluralize}/#{id}.json"
18
+ end
19
+
20
+ let(:create) do
21
+ post "/gatherable/#{prefix}#{model_name.to_s.pluralize}.json", params
22
+ end
23
+
24
+ let(:update) do
25
+ put "/gatherable/#{prefix}#{model_name.to_s.pluralize}/#{id}.json", params
26
+ end
27
+
28
+ let(:destroy) do
29
+ delete "/gatherable/#{prefix}#{model_name.to_s.pluralize}/#{id}.json"
6
30
  end
7
31
 
8
32
  let(:json_response) { JSON.parse(response.body) }
9
- let(:model_name) { :price }
10
- let(:data_table) { DataTable.find_by_name(model_name) }
11
- let(:model_class) { data_table.classify }
12
33
 
13
- describe '#index', :type => :request do
14
- def get_index
15
- get '/gatherable/session_id123/prices.json'
16
- end
34
+ before do
35
+ allow(SecureRandom).to receive(:urlsafe_base64) { global_id }
36
+ allow(data_table).to receive(:allowed_controller_actions) { [:show, :index, :create, :update, :destroy] }
37
+ @controller = controller_class.new
38
+ end
17
39
 
40
+ shared_examples "#index" do
18
41
  context 'successful request' do
19
- let(:model_params) { { "price" => "3.0"} }
20
- let(:price) { model_class.new(model_params.merge(:session_id => 'session_id123')) }
42
+ let(:instance) { model_class.new(model_params) }
43
+ let(:model_params) { { "#{model_name}_id" => 0, model_name.to_s => "3.0"} }
21
44
 
22
45
  before do
23
- allow(model_class).to receive(:where) { [price] }
46
+ allow(model_class).to receive(:where) { [instance] }
24
47
  end
25
48
 
26
- it 'returns a 201 response code' do
27
- get_index
49
+ it 'returns a 302 response code' do
50
+ index
28
51
  expect(response.status).to eql 302
29
52
  end
30
53
 
31
54
  it 'returns a json array' do
32
- get_index
33
- expect(json_response).to include({"price_id"=>nil, "price"=>"3.0", "session_id"=>"session_id123", "created_at"=>nil})
55
+ index
56
+ expect(json_response).to match([a_hash_including(model_params)])
34
57
  end
35
58
  end
36
59
 
37
60
  context 'unsuccesful request' do
38
- let(:perform_request) { lambda { get_index } }
61
+ context 'no results found' do
62
+ it 'returns an empty json response' do
63
+ index
64
+ expect(json_response).to be_empty
65
+ end
66
+ end
39
67
  end
40
68
  end
41
69
 
42
- describe '#show', :type => :request do
43
- let(:price) { Gatherable::Price.new(:price => 3.0) }
70
+ shared_examples '#show' do
71
+ let(:instance) { model_class.new(model_params) }
72
+ let(:model_params) { { model_name.to_s => "3.0", "#{model_name}_id" => id} }
44
73
 
45
74
  before do
46
- allow(model_class).to receive(:find_by!).with(:price_id => '1', :session_id => 'session_id123').and_return(price)
47
- allow(model_class).to receive(:find_by!).with(:price_id => '0', :session_id => 'session_id123').and_raise(ActiveRecord::RecordNotFound)
48
- end
49
-
50
- def do_get(price_id)
51
- get "/gatherable/session_id123/prices/#{price_id}.json"
75
+ allow(model_class).to receive(:find_by!).with("#{model_name}_id" => id.to_s, :session_id => global_id).and_return(instance)
76
+ allow(model_class).to receive(:find_by!).with("#{model_name}_id" => '0', :session_id => global_id).and_raise(ActiveRecord::RecordNotFound)
52
77
  end
53
78
 
54
79
  context 'record found' do
55
80
  before do
56
- do_get(1)
81
+ show
57
82
  end
58
83
 
59
84
  it 'returns the record' do
60
- expect(json_response).to eql \
61
- ({"price_id"=>nil, "price"=>"3.0", "session_id" => nil, "created_at"=>nil})
85
+ expect(json_response).to include(model_params)
62
86
  end
63
87
 
64
88
  specify 'the response code is 302' do
@@ -67,8 +91,9 @@ describe 'Gatherable::PricesController' do
67
91
  end
68
92
 
69
93
  context 'record not found' do
94
+ let(:id) { 0 }
70
95
  before do
71
- do_get(0)
96
+ show
72
97
  end
73
98
 
74
99
  specify 'the response code is 404' do
@@ -81,60 +106,58 @@ describe 'Gatherable::PricesController' do
81
106
  end
82
107
  end
83
108
 
84
- describe '#create', :type => :request do
85
- def do_post(params)
86
- post "/gatherable/session_id123/prices.json", params
87
- end
109
+ shared_examples '#create' do
88
110
 
89
111
  shared_examples 'successful object creation' do
112
+ let(:params) {{ model_name => model_params }}
90
113
  before do
91
- model_params.merge!('session_id' => 'session_id123')
114
+ model_params.merge!('session_id' => global_id)
92
115
  end
93
116
 
94
117
  it 'creates an object' do
95
118
  expect(model_class).to receive(:create!).with(model_params)
96
- do_post({:price => model_params })
119
+ create
97
120
  end
98
121
 
99
122
  it "contains all attributes of the model" do
100
- do_post(passed_params)
123
+ create
101
124
  model_class.column_names.each do |attr|
102
125
  expect(json_response.keys).to include(attr)
103
126
  end
104
127
  end
105
128
 
106
129
  it "returns the saved values of the created model" do
107
- do_post(passed_params)
108
- model_params.each do |(attr, val)|
130
+ create
131
+ model_params.stringify_keys.each do |(attr, val)|
109
132
  expect(json_response[attr]).to eql val
110
133
  end
111
134
  end
112
135
 
113
136
  it 'adds a timestamp to the record' do
114
- do_post(passed_params)
137
+ create
115
138
  expect(json_response['created_at']).to_not be_nil
116
139
  end
117
140
 
118
141
  specify 'the object created is valid' do
119
- do_post(passed_params)
120
- expect(price).to be_valid
142
+ create
143
+ expect(instance).to be_valid
121
144
  end
122
145
 
123
146
  specify 'status is 201' do
124
- do_post(passed_params)
147
+ create
125
148
  expect(response.status).to eql 201
126
149
  end
127
150
 
128
151
  context 'new_record_strategy = :update' do
129
152
  before do
130
- allow(DataTable.find_by_name(model_name)).to receive(:new_record_strategy).and_return :update
153
+ allow(data_table).to receive(:new_record_strategy).and_return :update
131
154
  end
132
155
 
133
156
  context 'updating existing record' do
134
157
  let!(:existing_record) { model_class.create(model_name => '76', :session_id => 'session_id123') }
135
158
 
136
159
  it 'sets correct values' do
137
- do_post(passed_params)
160
+ create
138
161
  existing_record.reload
139
162
  model_params.each do |(attr, val)|
140
163
  expect(existing_record.send(attr).to_s).to eql val
@@ -142,126 +165,135 @@ describe 'Gatherable::PricesController' do
142
165
  end
143
166
 
144
167
  it 'does not create a new record' do
145
- expect{do_post(passed_params)}.to_not change{model_class.count}
168
+ expect{create}.to_not change{model_class.count}
146
169
  end
147
170
  end
148
171
 
149
172
  context 'creating new record' do
150
173
  it 'creates a valid record' do
151
- expect{do_post(passed_params)}.to change{model_class.count}.by 1
174
+ expect{create}.to change{model_class.count}.by 1
152
175
  end
153
176
  end
154
177
 
155
178
  specify 'status is 200' do
156
- do_post(passed_params)
179
+ create
157
180
  expect(response.status).to eql 200
158
181
  end
159
182
  end
160
183
  end
161
184
 
162
185
  context 'correct param format' do
163
- let(:model_params) { { "price" => "3.0"} }
164
- let(:passed_params) { {:price => model_params} }
165
- let(:price) { model_class.new(model_params.merge(:session_id => 'session_id123')) }
186
+ let(:model_params) { { model_name => "3.0"} }
187
+ let(:instance) { model_class.new(model_params) }
166
188
  it_behaves_like 'successful object creation'
167
189
  end
168
190
 
169
- context 'auth_method set' do
170
- let(:model_params) { { "price" => "3.0"} }
171
- let(:passed_params) { {:price => model_params} }
172
- let(:model_name) { :price }
173
- context 'session identifier matches passed identifier' do
174
- before do
175
- allow(Gatherable.config).to receive(:auth_method) { :session }
176
- session[:session_id] = 'session_id123'
177
- allow_any_instance_of(@controller.class).to receive(:session) { session } #boo any_instance
178
- end
179
- let(:price) { model_class.new(model_params.merge(:session_id => 'session_id123')) }
180
- it_behaves_like 'successful object creation'
181
- end
182
-
183
- context 'session identifier does not match passed identifier' do
184
- before do
185
- allow(Gatherable.config).to receive(:auth_method) { :session }
186
- do_post(passed_params)
187
- end
188
-
189
- it 'returns an empty response body' do
190
- expect(response.body).to be_empty
191
- end
192
-
193
- it 'gives an unauthorized response status' do
194
- expect(response.status).to eql 401
195
- end
196
-
197
- it 'does not create an object' do
198
- expect(model_class).to_not receive(:create!)
199
- do_post(passed_params)
200
- end
201
- end
202
- end
203
191
 
204
192
  context 'incorrect param format' do
205
193
  context 'required params not given' do
194
+ let(:params) { { :yolo => 'swag' } }
206
195
  specify 'the response status is 422' do
207
- do_post( { :yolo => 'swag' } )
196
+ create
208
197
  expect(response.status).to eql 422
209
198
  end
210
199
  end
211
200
 
212
201
  context 'required params + junk params given' do
213
- let(:model_params) { { "price" => "3.0"} }
202
+ let(:model_params) { { model_name => "3.0"} }
214
203
  let(:junk_params) { { 'yolo' => 'swag' } }
215
- let(:passed_params) { {:price => model_params.merge(junk_params)}.merge(junk_params) }
216
- let(:price) { model_class.new(model_params.merge(:session_id => 'session_id123')) }
204
+ let(:params) { { model_name => model_params.merge(junk_params)}.merge(junk_params) }
205
+ let(:instance) { model_class.new(model_params.merge(:session_id => 'session_id123')) }
217
206
  it_behaves_like 'successful object creation'
218
207
  end
219
208
  end
220
209
  end
221
210
 
222
- describe '#update', :type => :request do
223
- let(:price) { model_class.new(model_params.merge(:session_id => 'session_id123')) }
224
- let(:bad_params) { { 'price' => 'free' } }
225
- let(:model_params) { { 'price' => '3.0' } }
211
+ shared_examples '#update' do
212
+ describe '#update' do
213
+ let(:model_params) { { model_name => '3.0', "#{model_name}_id" => id } }
214
+ let(:instance) { model_class.new(model_params) }
215
+ let(:params) { { model_name => { model_name => '4.0' } } }
226
216
 
227
- def update(id, params)
228
- put "/gatherable/session_id123/prices/#{id}.json", params
229
- end
217
+ context 'successful request' do
218
+ before do
219
+ instance.save!
220
+ update
221
+ end
230
222
 
231
- context 'successful request' do
232
- before do
233
- price.save!
234
- update(price.reload.id, 'price' => {'price' => 11 })
223
+ it 'updates the record' do
224
+ expect(instance.reload.send(model_name.to_sym).to_s).to eql '4.0'
225
+ end
226
+
227
+ it 'renders an updated version of the record' do
228
+ expect(json_response).to include( {model_name.to_s => '4.0'} )
229
+ end
235
230
  end
236
231
 
237
- it 'updates the record' do
238
- expect(price.reload.price).to eql 11
232
+ context 'with invalid data' do
233
+ let(:params) { { model_name => Date.today } }
234
+
235
+ before do
236
+ allow(model_class).to receive(:find_by!).and_return(instance)
237
+ update
238
+ end
239
+
240
+ specify 'the response code is 422' do
241
+ expect(response.status).to eql 422
242
+ end
243
+
244
+ it 'returns errors' do
245
+ expect(json_response).to have_key('errors')
246
+ end
239
247
  end
240
248
 
241
- it 'renders an updated version of the record' do
242
- expect(json_response).to include( {"price_id"=>29, "price"=>"11.0", "session_id"=>"session_id123"} )
249
+ context 'record not found' do
250
+ let(:id) { 0 }
251
+ let(:params) { {} }
252
+ before do
253
+ update
254
+ end
255
+
256
+ specify 'the response code is 404' do
257
+ expect(response.status).to eql 404
258
+ end
259
+
260
+ it 'returns errors' do
261
+ expect(json_response).to eql({"errors"=>"Couldn't find Gatherable::#{model_name.to_s.classify}"})
262
+ end
243
263
  end
244
264
  end
265
+ end
245
266
 
246
- context 'with invalid data' do
267
+ shared_examples '#destroy' do
268
+ let(:model_params) { { model_name => '3.0' } }
269
+ let(:instance) { model_class.new(model_params.merge(:session_id => 'session_id123')) }
270
+ let(:id) { instance.reload.id }
247
271
 
272
+ context 'successful request' do
248
273
  before do
249
- allow(model_class).to receive(:find_by!).with(:price_id => '1', :session_id => 'session_id123').and_return(price)
250
- update(1, bad_params)
274
+ instance.save!
275
+ id
276
+ destroy
251
277
  end
252
278
 
253
- specify 'the response code is 422' do
254
- expect(response.status).to eql 422
279
+ it 'deletes the record' do
280
+ expect(model_class.where("#{model_name}_id" => id)).to be_empty
255
281
  end
256
282
 
257
- it 'returns errors' do
258
- expect(json_response).to have_key('errors')
283
+ it 'renders nothing' do
284
+ expect(response.body).to be_empty
285
+ end
286
+
287
+ it 'has a successful response code' do
288
+ expect(response.status).to eql 204
259
289
  end
260
290
  end
261
291
 
262
292
  context 'record not found' do
293
+ let(:id) { 0 }
294
+
263
295
  before do
264
- update(0, {})
296
+ destroy
265
297
  end
266
298
 
267
299
  specify 'the response code is 404' do
@@ -269,46 +301,128 @@ describe 'Gatherable::PricesController' do
269
301
  end
270
302
 
271
303
  it 'returns errors' do
272
- expect(json_response).to eql({"errors"=>"Couldn't find Gatherable::Price"})
304
+ expect(json_response).to eql({"errors"=>"Couldn't find Gatherable::#{model_name.to_s.classify}"})
273
305
  end
274
306
  end
275
307
  end
276
308
 
277
- describe '#delete', :type => :request do
278
- let(:price) { model_class.new(model_params.merge(:session_id => 'session_id123')) }
279
- let(:bad_params) { { 'price' => 'free' } }
280
- let(:model_params) { { 'price' => '3.0' } }
309
+ shared_examples 'auth failed' do
310
+ let(:prefix) { "#{global_id}123/" }
281
311
 
282
- def delete_price(id)
283
- delete "/gatherable/session_id123/prices/#{id}.json"
312
+ before do
313
+ allow(Gatherable.config).to receive(:auth_method) { :session }
314
+ allow_any_instance_of(@controller.class).to receive(:session) { {:session_id => global_id } }
315
+ perform_request.call
284
316
  end
285
317
 
286
- context 'successful request' do
287
- before do
288
- price.save!
318
+ it 'returns an empty body' do
319
+ expect(response.body).to be_empty
320
+ end
321
+
322
+ it 'returns a response status of unauthorized' do
323
+ expect(response.status).to eql 401
324
+ end
325
+ end
326
+
327
+ context 'unique identifier required in route' do
328
+ let(:prefix) { "#{global_id}/" }
329
+
330
+ before do
331
+ allow(Gatherable.config).to receive(:prefixed_resources) { [data_table.name] }
332
+ Gatherable::RouteDrawer.draw
333
+ end
334
+
335
+ it_behaves_like '#index' do
336
+ it_behaves_like 'auth failed' do
337
+ let(:perform_request) { Proc.new{index} }
289
338
  end
339
+ end
290
340
 
291
- it 'deletes the record' do
292
- delete_price(price.id)
293
- expect(Gatherable::Price.where(price_id: price.id)).to be_empty
341
+ it_behaves_like '#show' do
342
+ it_behaves_like 'auth failed' do
343
+ let(:perform_request) { Proc.new{index} }
294
344
  end
345
+ end
295
346
 
296
- it 'renders nothing' do
297
- expect(response.body).to be_empty
347
+ it_behaves_like '#create' do
348
+ it_behaves_like 'auth failed' do
349
+ let(:perform_request) { Proc.new{ create } }
350
+ let(:params) { {} }
351
+
352
+ it 'does not create an object' do
353
+ expect{perform_request.call}.to_not change{model_class.count}
354
+ end
298
355
  end
299
356
  end
300
357
 
301
- context 'record not found' do
358
+ it_behaves_like '#update' do
359
+ it_behaves_like 'auth failed' do
360
+ let(:perform_request) { Proc.new{ update } }
361
+ let(:params) { {} }
362
+ let(:instance) { model_class.new(model_name => '3.0', :session_id => global_id) }
363
+ let!(:id) { instance.save!; instance.reload.id }
364
+
365
+ before do
366
+ allow(model_class).to receive(:find_by!) { instance }
367
+ end
368
+
369
+ it 'does not update the instance' do
370
+ perform_request.call
371
+ expect(instance).to eql instance.reload
372
+ end
373
+ end
374
+ end
375
+
376
+ it_behaves_like '#destroy' do
377
+ it_behaves_like 'auth failed' do
378
+ let(:perform_request) { Proc.new{ destroy } }
379
+ let(:instance) { model_class.new(model_name => '3.0', :session_id => global_id) }
380
+ let!(:id) { instance.save!; instance.reload.id }
381
+
382
+ before do
383
+ allow(model_class).to receive(:find_by!) { instance }
384
+ end
385
+
386
+ it 'does not delete the instance' do
387
+ expect{perform_request.call}.to_not change{instance.persisted?}
388
+ end
389
+ end
390
+ end
391
+ end
392
+
393
+ context 'unique identifier not required in route' do
394
+ let(:prefix) { '' }
395
+
396
+ before do
397
+ allow(Gatherable.config).to receive(:prefixed_resources) { [] }
398
+ Gatherable::RouteDrawer.draw
399
+ end
400
+
401
+ it_behaves_like '#index'
402
+ it_behaves_like '#show'
403
+ it_behaves_like '#create'
404
+ it_behaves_like '#update'
405
+ it_behaves_like '#destroy'
406
+ end
407
+
408
+ [:index, :show, :create, :update, :destroy].each do |disallowed_action|
409
+ context "#{disallowed_action} not allowed" do
410
+ let(:all_actions) { [:index, :show, :create, :update, :destroy] }
411
+ let(:prefix) { }
412
+ let(:params) { {} }
413
+
302
414
  before do
303
- delete_price(0)
415
+ allow(data_table).to receive(:allowed_controller_actions).and_return(all_actions - [disallowed_action])
416
+ Gatherable::RouteDrawer.draw
304
417
  end
305
418
 
306
- specify 'the response code is 404' do
307
- expect(response.status).to eql 404
419
+ specify "sending #{disallowed_action} raises error" do
420
+ expect{send(disallowed_action)}.to raise_error(ActionController::RoutingError)
308
421
  end
309
422
 
310
- it 'returns errors' do
311
- expect(json_response).to eql({"errors"=>"Couldn't find Gatherable::Price"})
423
+ after do
424
+ allow(data_table).to receive(:allowed_controller_actions) { all_actions }
425
+ Gatherable::RouteDrawer.draw
312
426
  end
313
427
  end
314
428
  end