wor-simple_crud 0.5.0 → 0.7.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 +4 -4
- data/CHANGELOG.md +37 -0
- data/Gemfile +5 -1
- data/README.md +104 -8
- data/lib/simple_crud/action_context.rb +45 -10
- data/lib/simple_crud/create_context.rb +2 -1
- data/lib/simple_crud/destroy_context.rb +2 -1
- data/lib/simple_crud/index_context.rb +30 -12
- data/lib/simple_crud/pagination/wor_paginate_adapter.rb +7 -1
- data/lib/simple_crud/persistence_context.rb +33 -6
- data/lib/simple_crud/relation_source.rb +107 -0
- data/lib/simple_crud/rspec/config.rb +6 -1
- data/lib/simple_crud/rspec/helpers/authentication.rb +2 -1
- data/lib/simple_crud/rspec/helpers/controller_options.rb +2 -2
- data/lib/simple_crud/rspec/helpers/requests.rb +5 -2
- data/lib/simple_crud/rspec.rb +2 -0
- data/lib/simple_crud/serializer.rb +14 -0
- data/lib/simple_crud/show_context.rb +3 -1
- data/lib/simple_crud/simple_crud_controller.rb +29 -6
- data/lib/simple_crud/update_context.rb +2 -1
- data/lib/simple_crud/version.rb +1 -1
- data/lib/spec/matchers/have_been_serialized_with.rb +19 -2
- data/lib/spec/shared_examples/simple_crud_for_create.rb +6 -6
- data/lib/spec/shared_examples/simple_crud_for_create_with_block.rb +2 -2
- data/lib/spec/shared_examples/simple_crud_for_create_with_build.rb +1 -1
- data/lib/spec/shared_examples/simple_crud_for_destroy.rb +8 -8
- data/lib/spec/shared_examples/simple_crud_for_destroy_with_block.rb +1 -1
- data/lib/spec/shared_examples/simple_crud_for_destroy_with_finder.rb +3 -3
- data/lib/spec/shared_examples/simple_crud_for_edit.rb +2 -2
- data/lib/spec/shared_examples/simple_crud_for_index.rb +3 -3
- data/lib/spec/shared_examples/simple_crud_for_index_with_block.rb +1 -1
- data/lib/spec/shared_examples/simple_crud_for_index_with_scope.rb +1 -1
- data/lib/spec/shared_examples/simple_crud_for_nested_resource.rb +21 -0
- data/lib/spec/shared_examples/simple_crud_for_new.rb +1 -1
- data/lib/spec/shared_examples/simple_crud_for_new_with_block.rb +1 -1
- data/lib/spec/shared_examples/simple_crud_for_new_with_build.rb +1 -1
- data/lib/spec/shared_examples/simple_crud_for_owned_resource.rb +35 -0
- data/lib/spec/shared_examples/simple_crud_for_show.rb +2 -2
- data/lib/spec/shared_examples/simple_crud_for_show_with_block.rb +1 -1
- data/lib/spec/shared_examples/simple_crud_for_show_with_finder.rb +1 -1
- data/lib/spec/shared_examples/simple_crud_for_update.rb +7 -7
- data/lib/spec/shared_examples/simple_crud_for_update_with_finder.rb +1 -1
- data/lib/spec/shared_examples/simple_crud_not_found_with_finder.rb +1 -1
- data/spec/blueprint/dummy_models_controller_spec.rb +25 -0
- data/spec/blueprint_unpaginated/dummy_models_controller_spec.rb +9 -0
- data/spec/dummy/app/blueprints/dummy_model_blueprint.rb +10 -0
- data/spec/dummy/app/controllers/blueprint/dummy_models_controller.rb +21 -0
- data/spec/dummy/app/controllers/blueprint_unpaginated/dummy_models_controller.rb +10 -0
- data/spec/dummy/app/controllers/html_notice/dummy_models_controller.rb +11 -0
- data/spec/dummy/app/controllers/owned/dummy_models_controller.rb +21 -0
- data/spec/dummy/app/controllers/parented/dummy_models_controller.rb +23 -0
- data/spec/dummy/app/controllers/scoped_symbol/dummy_models_controller.rb +11 -0
- data/spec/dummy/app/models/dummy_model.rb +4 -0
- data/spec/dummy/app/serializers/dummy_model_plain_serializer.rb +8 -0
- data/spec/dummy/app/views/html_notice/dummy_models/edit.html.erb +1 -0
- data/spec/dummy/config/routes.rb +24 -0
- data/spec/dummy_model_blueprint_spec.rb +16 -0
- data/spec/html_notice/dummy_models_controller_spec.rb +38 -0
- data/spec/owned/dummy_models_controller_spec.rb +12 -0
- data/spec/parented/dummy_models_controller_spec.rb +29 -0
- data/spec/scoped_symbol/dummy_models_controller_spec.rb +7 -0
- data/spec/simple_crud/action_context_spec.rb +34 -0
- data/spec/simple_crud/index_context_spec.rb +49 -0
- data/spec/simple_crud/relation_source_spec.rb +125 -0
- data/spec/simple_crud/rspec_config_spec.rb +13 -0
- data/spec/simple_crud/serializer_spec.rb +49 -0
- data/spec/simple_crud/show_context_spec.rb +5 -0
- data/spec/simple_crud_controller_spec.rb +15 -0
- metadata +25 -3
|
@@ -11,8 +11,11 @@ module SimpleCrud
|
|
|
11
11
|
Rack::Utils::SYMBOL_TO_STATUS_CODE.invert[422]
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
# Rails copies the controller-test `format:` kwarg into params, which
|
|
15
|
+
# collides with a model attribute named `format`. Only HTML requests
|
|
16
|
+
# need it, so leave params untouched for JSON.
|
|
17
|
+
def format_param(action)
|
|
18
|
+
check_html(action) ? :html : nil
|
|
16
19
|
end
|
|
17
20
|
|
|
18
21
|
# Extra params (e.g. a parent slug) added to every request, for nested
|
data/lib/simple_crud/rspec.rb
CHANGED
|
@@ -27,6 +27,8 @@ require_relative '../spec/shared_examples/simple_crud_for_destroy_with_finder'
|
|
|
27
27
|
require_relative '../spec/shared_examples/simple_crud_not_found_with_finder'
|
|
28
28
|
require_relative '../spec/shared_examples/simple_crud_for_new_with_build'
|
|
29
29
|
require_relative '../spec/shared_examples/simple_crud_for_create_with_build'
|
|
30
|
+
require_relative '../spec/shared_examples/simple_crud_for_owned_resource'
|
|
31
|
+
require_relative '../spec/shared_examples/simple_crud_for_nested_resource'
|
|
30
32
|
require_relative '../spec/shared_examples/authorization_adapter_authorize'
|
|
31
33
|
require_relative '../spec/matchers/have_been_serialized_with'
|
|
32
34
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SimpleCrud
|
|
4
|
+
# Precedence: Blueprinter, then a plain class .render, then ActiveModelSerializers.
|
|
5
|
+
module Serializer
|
|
6
|
+
def self.render(serializer, record, options = {})
|
|
7
|
+
return record.as_json if serializer.nil?
|
|
8
|
+
return serializer.render_as_hash(record, options) if serializer.respond_to?(:render_as_hash)
|
|
9
|
+
return serializer.render(record, **options) if serializer.is_a?(Class) && serializer.respond_to?(:render)
|
|
10
|
+
|
|
11
|
+
serializer.new(record, options).as_json
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -21,7 +21,9 @@ module SimpleCrud
|
|
|
21
21
|
record = find_record
|
|
22
22
|
maybe_authorize(record)
|
|
23
23
|
controller.instance_variable_set(:@record, record)
|
|
24
|
-
|
|
24
|
+
return controller.instance_exec(record, &block) if block
|
|
25
|
+
|
|
26
|
+
SimpleCrud::Serializer.render(parameters[:serializer], record, serializer_options(record))
|
|
25
27
|
end
|
|
26
28
|
end
|
|
27
29
|
end
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
require 'active_support/all'
|
|
4
4
|
require_relative 'config'
|
|
5
|
+
require_relative 'serializer'
|
|
5
6
|
require_relative 'cache_helpers'
|
|
7
|
+
require_relative 'relation_source'
|
|
6
8
|
require_relative 'action_context'
|
|
7
9
|
require_relative 'persistence_context'
|
|
8
10
|
require_relative 'show_context'
|
|
@@ -31,16 +33,26 @@ module SimpleCrudController
|
|
|
31
33
|
### serializer: use a particular serializer (both each_serializer and serializer)
|
|
32
34
|
### html: render the action's ERB template instead of JSON (index/show/new/edit/create/update/destroy)
|
|
33
35
|
### finder: custom record lookup (Proc/lambda or Symbol) for :show/:update/:destroy/:edit
|
|
34
|
-
### scope: custom index scope
|
|
36
|
+
### scope: custom index scope for :index, overriding policy_scope. A Proc/lambda run with the
|
|
37
|
+
### controller as self (arity 0 no args, arity 1 the user, else user and params), or a Symbol
|
|
38
|
+
### naming a model class method taking (current_user, params)
|
|
35
39
|
### build: custom record builder (Proc/lambda) for :new/:create, invoked with the controller as self
|
|
40
|
+
### owned_by: association on Config.user_method for the default finder/build/index-scope
|
|
41
|
+
### parent: nested-route parent for the same defaults; exclusive with owned_by:
|
|
42
|
+
### parent_association: parent association when it differs from the controller model's plural
|
|
43
|
+
### notice:/alert: flash on the html: create/update/destroy success redirect / failure re-render
|
|
36
44
|
### raise_on_invalid: use strict create!/update! semantics instead of returning 422
|
|
37
45
|
### A block given to simple_crud_for renders explicitly: it receives the records for :index,
|
|
38
46
|
### the record for :show/:new/:edit, or the record and a saved flag for :create/:update/:destroy
|
|
47
|
+
### An Array of actions declares several at once with the same options
|
|
39
48
|
def simple_crud_for(method, parameters = {}, &block)
|
|
49
|
+
return method.each { |name| simple_crud_for(name, parameters.dup, &block) } if method.is_a?(Array)
|
|
50
|
+
|
|
40
51
|
parameters[:block] = true if block
|
|
41
52
|
parameters = parameters_with_defaults(parameters)
|
|
42
53
|
klass = simple_crud_controller_model
|
|
43
54
|
check_valid_method(method)
|
|
55
|
+
check_relation_source(parameters)
|
|
44
56
|
check_policies(parameters)
|
|
45
57
|
check_serializer(parameters)
|
|
46
58
|
define_method(method, send("crud_lambda_for_#{method}", klass, parameters, &block))
|
|
@@ -61,17 +73,22 @@ module SimpleCrudController
|
|
|
61
73
|
end
|
|
62
74
|
|
|
63
75
|
def parameters_with_defaults(parameters)
|
|
64
|
-
defaults = {
|
|
65
|
-
authorize: true, paginate: true, authenticate: true, authenticate_headers: nil,
|
|
66
|
-
serializer: nil, html: false, finder: nil, scope: nil, build: nil, raise_on_invalid: false
|
|
67
|
-
}
|
|
68
76
|
defaults.merge(simple_crud_inherited_defaults).each do |key, value|
|
|
69
77
|
parameters[key] = value unless parameters.key?(key)
|
|
70
78
|
end
|
|
71
|
-
parameters[:authenticate_headers]
|
|
79
|
+
parameters[:authenticate_headers] ||= parameters[:authenticate]
|
|
72
80
|
parameters
|
|
73
81
|
end
|
|
74
82
|
|
|
83
|
+
def defaults
|
|
84
|
+
{
|
|
85
|
+
authorize: true, paginate: true, authenticate: true, authenticate_headers: nil,
|
|
86
|
+
serializer: nil, serializer_options: nil, status: nil, after_persist: nil, html: false,
|
|
87
|
+
finder: nil, scope: nil, build: nil, owned_by: nil, parent: nil, parent_association: nil,
|
|
88
|
+
notice: nil, alert: nil, raise_on_invalid: false
|
|
89
|
+
}
|
|
90
|
+
end
|
|
91
|
+
|
|
75
92
|
def write_metadata(method, parameters)
|
|
76
93
|
@simple_crud_metadata ||= {}
|
|
77
94
|
@simple_crud_metadata[method] = parameters
|
|
@@ -85,6 +102,12 @@ module SimpleCrudController
|
|
|
85
102
|
raise ArgumentError, 'invalid method' unless %i[show index create update destroy new edit].include? method
|
|
86
103
|
end
|
|
87
104
|
|
|
105
|
+
def check_relation_source(parameters)
|
|
106
|
+
return unless parameters[:owned_by] && parameters[:parent]
|
|
107
|
+
|
|
108
|
+
raise ArgumentError, 'owned_by: and parent: are mutually exclusive, they both scope the same action'
|
|
109
|
+
end
|
|
110
|
+
|
|
88
111
|
def check_policies(parameters)
|
|
89
112
|
return if !parameters.key?(:authorize) || !parameters[:authorize]
|
|
90
113
|
|
|
@@ -9,7 +9,8 @@ module SimpleCrud
|
|
|
9
9
|
maybe_authorize(record)
|
|
10
10
|
attrs = permitted_params
|
|
11
11
|
persist = ->(bang:) { bang ? record.update!(attrs) : record.update(attrs) }
|
|
12
|
-
options = { status: :ok, failure_template: :edit,
|
|
12
|
+
options = { status: parameters[:status] || :ok, failure_template: :edit,
|
|
13
|
+
redirect: parameters[:redirect] || record }
|
|
13
14
|
persist_and_render(record, options, persist)
|
|
14
15
|
end
|
|
15
16
|
end
|
data/lib/simple_crud/version.rb
CHANGED
|
@@ -4,12 +4,29 @@ RSpec::Matchers.define :have_been_serialized_with do |serializer|
|
|
|
4
4
|
# TODO: Add support for optional relations `has_many :zarasa, if: zarasa2`
|
|
5
5
|
# TODO: Support multilevel serialization
|
|
6
6
|
match do |json_response|
|
|
7
|
+
attributes = serializer_attributes(serializer)
|
|
8
|
+
reflections = serializer_reflections(serializer)
|
|
9
|
+
|
|
7
10
|
[json_response].flatten.all? do |json_response_item|
|
|
8
|
-
all_attributes_included?(
|
|
9
|
-
all_attributes_included?(
|
|
11
|
+
all_attributes_included?(attributes, json_response_item) &&
|
|
12
|
+
all_attributes_included?(reflections, json_response_item)
|
|
10
13
|
end
|
|
11
14
|
end
|
|
12
15
|
|
|
16
|
+
# Blueprinter blueprints expose their fields through the view collection;
|
|
17
|
+
# ActiveModelSerializers expose `._attributes` / `._reflections`.
|
|
18
|
+
def serializer_attributes(serializer)
|
|
19
|
+
return serializer._attributes unless serializer.respond_to?(:view_collection)
|
|
20
|
+
|
|
21
|
+
serializer.view_collection.fields_for(:default).map(&:name)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def serializer_reflections(serializer)
|
|
25
|
+
return serializer._reflections.keys unless serializer.respond_to?(:view_collection)
|
|
26
|
+
|
|
27
|
+
[]
|
|
28
|
+
end
|
|
29
|
+
|
|
13
30
|
failure_message do |json_response|
|
|
14
31
|
"expected attributes of #{serializer} serializer to be included in #{json_response}"
|
|
15
32
|
end
|
|
@@ -4,7 +4,7 @@ RSpec.shared_examples 'simple crud for create' do
|
|
|
4
4
|
describe 'POST #create' do
|
|
5
5
|
context 'without authenticated user' do
|
|
6
6
|
subject!(:req) do
|
|
7
|
-
post :create, params: with_route_params(body_params(params_for(model_class))), format:
|
|
7
|
+
post :create, params: with_route_params(body_params(params_for(model_class))), format: format_param(:create)
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
include_examples 'unauthorized when not logged in' if check_authenticate(:create)
|
|
@@ -16,7 +16,7 @@ RSpec.shared_examples 'simple crud for create' do
|
|
|
16
16
|
|
|
17
17
|
before do
|
|
18
18
|
make_policies_fail(:create)
|
|
19
|
-
post :create, params: with_route_params(body_params(model_params)), format:
|
|
19
|
+
post :create, params: with_route_params(body_params(model_params)), format: format_param(:create)
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
it 'fails with forbidden' do
|
|
@@ -30,7 +30,7 @@ RSpec.shared_examples 'simple crud for create' do
|
|
|
30
30
|
let(:create_params) { model_params.merge(owner_params) }
|
|
31
31
|
|
|
32
32
|
before do
|
|
33
|
-
post :create, params: with_route_params(body_params(create_params)), format:
|
|
33
|
+
post :create, params: with_route_params(body_params(create_params)), format: format_param(:create)
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
if check_html(:create)
|
|
@@ -38,8 +38,8 @@ RSpec.shared_examples 'simple crud for create' do
|
|
|
38
38
|
expect(response).to have_http_status(:found)
|
|
39
39
|
end
|
|
40
40
|
else
|
|
41
|
-
it 'response with
|
|
42
|
-
expect(response).to have_http_status(:created)
|
|
41
|
+
it 'response with the configured status code' do
|
|
42
|
+
expect(response).to have_http_status(check_status(:create) || :created)
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
it 'creates an article with valid attributes' do
|
|
@@ -58,7 +58,7 @@ RSpec.shared_examples 'simple crud for create' do
|
|
|
58
58
|
include_context 'with authenticated user' if check_authenticate(:create)
|
|
59
59
|
|
|
60
60
|
before do
|
|
61
|
-
post :create, params: with_route_params(body_params(owner_params)), format:
|
|
61
|
+
post :create, params: with_route_params(body_params(owner_params)), format: format_param(:create)
|
|
62
62
|
end
|
|
63
63
|
|
|
64
64
|
unless check_block(:create)
|
|
@@ -7,7 +7,7 @@ RSpec.shared_examples 'simple crud for create with block' do
|
|
|
7
7
|
let(:create_params) { model_params.merge(owner_params) }
|
|
8
8
|
|
|
9
9
|
before do
|
|
10
|
-
post :create, params: with_route_params(body_params(create_params)), format:
|
|
10
|
+
post :create, params: with_route_params(body_params(create_params)), format: format_param(:create)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
it 'passes the saved record to the block' do
|
|
@@ -24,7 +24,7 @@ RSpec.shared_examples 'simple crud for create with block' do
|
|
|
24
24
|
include_context 'with authenticated user' if check_authenticate(:create)
|
|
25
25
|
|
|
26
26
|
before do
|
|
27
|
-
post :create, params: with_route_params(body_params(owner_params)), format:
|
|
27
|
+
post :create, params: with_route_params(body_params(owner_params)), format: format_param(:create)
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
it 'does not create a model' do
|
|
@@ -5,7 +5,7 @@ RSpec.shared_examples 'simple crud for create with build' do
|
|
|
5
5
|
include_context 'with authenticated user' if check_authenticate(:create)
|
|
6
6
|
|
|
7
7
|
before do
|
|
8
|
-
post :create, params: with_route_params(body_params(params_for(model_class))), format:
|
|
8
|
+
post :create, params: with_route_params(body_params(params_for(model_class))), format: format_param(:create)
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
it 'creates the record owned by the current user' do
|
|
@@ -5,7 +5,7 @@ RSpec.shared_examples 'simple crud for destroy' do
|
|
|
5
5
|
context 'without authenticated user' do
|
|
6
6
|
subject!(:req) do
|
|
7
7
|
delete :destroy, params: with_route_params(record_param(:destroy, nil, not_found: true)),
|
|
8
|
-
format:
|
|
8
|
+
format: format_param(:destroy)
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
include_examples 'unauthorized when not logged in' if check_authenticate(:destroy)
|
|
@@ -17,7 +17,7 @@ RSpec.shared_examples 'simple crud for destroy' do
|
|
|
17
17
|
|
|
18
18
|
before do
|
|
19
19
|
make_policies_fail(:destroy)
|
|
20
|
-
delete :destroy, params: with_route_params(record_param(:destroy, model)), format:
|
|
20
|
+
delete :destroy, params: with_route_params(record_param(:destroy, model)), format: format_param(:destroy)
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
it 'fails with forbidden' do
|
|
@@ -31,7 +31,7 @@ RSpec.shared_examples 'simple crud for destroy' do
|
|
|
31
31
|
|
|
32
32
|
before do
|
|
33
33
|
model
|
|
34
|
-
delete :destroy, params: with_route_params(record_param(:destroy, model)), format:
|
|
34
|
+
delete :destroy, params: with_route_params(record_param(:destroy, model)), format: format_param(:destroy)
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
if check_html(:destroy)
|
|
@@ -40,8 +40,8 @@ RSpec.shared_examples 'simple crud for destroy' do
|
|
|
40
40
|
expect(model_class_object.exists?(model.id)).to be false
|
|
41
41
|
end
|
|
42
42
|
else
|
|
43
|
-
it 'response with
|
|
44
|
-
expect(response).to have_http_status(:ok)
|
|
43
|
+
it 'response with the configured status code' do
|
|
44
|
+
expect(response).to have_http_status(check_status(:destroy) || :ok)
|
|
45
45
|
end
|
|
46
46
|
end
|
|
47
47
|
end
|
|
@@ -53,7 +53,7 @@ RSpec.shared_examples 'simple crud for destroy' do
|
|
|
53
53
|
model
|
|
54
54
|
allow(model).to receive(:destroy).and_return(false)
|
|
55
55
|
allow_any_instance_of(SimpleCrud::DestroyContext).to receive(:find_record).and_return(model)
|
|
56
|
-
delete :destroy, params: with_route_params(record_param(:destroy, model)), format:
|
|
56
|
+
delete :destroy, params: with_route_params(record_param(:destroy, model)), format: format_param(:destroy)
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
it 'keeps the record' do
|
|
@@ -77,7 +77,7 @@ RSpec.shared_examples 'simple crud for destroy' do
|
|
|
77
77
|
before do
|
|
78
78
|
model
|
|
79
79
|
delete :destroy, params: with_route_params(record_param(:destroy, nil, not_found: true)),
|
|
80
|
-
format:
|
|
80
|
+
format: format_param(:destroy)
|
|
81
81
|
end
|
|
82
82
|
|
|
83
83
|
it 'responds with not found status' do
|
|
@@ -92,7 +92,7 @@ RSpec.shared_examples 'simple crud for destroy' do
|
|
|
92
92
|
before do
|
|
93
93
|
model
|
|
94
94
|
make_policies_fail(:destroy)
|
|
95
|
-
delete :destroy, params: with_route_params(record_param(:destroy, model)), format:
|
|
95
|
+
delete :destroy, params: with_route_params(record_param(:destroy, model)), format: format_param(:destroy)
|
|
96
96
|
end
|
|
97
97
|
|
|
98
98
|
it 'responds with forbidden status' do
|
|
@@ -7,7 +7,7 @@ RSpec.shared_examples 'simple crud for destroy with block' do
|
|
|
7
7
|
let!(:record) { model }
|
|
8
8
|
|
|
9
9
|
before do
|
|
10
|
-
delete :destroy, params: with_route_params(record_param(:destroy, record)), format:
|
|
10
|
+
delete :destroy, params: with_route_params(record_param(:destroy, record)), format: format_param(:destroy)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
it 'passes the destroyed record to the block' do
|
|
@@ -8,7 +8,7 @@ RSpec.shared_examples 'simple crud for destroy with finder' do
|
|
|
8
8
|
before do
|
|
9
9
|
model
|
|
10
10
|
delete :destroy, params: with_route_params(finder_key => model.public_send(finder_key)),
|
|
11
|
-
format:
|
|
11
|
+
format: format_param(:destroy)
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
it 'destroys the model' do
|
|
@@ -24,8 +24,8 @@ RSpec.shared_examples 'simple crud for destroy with finder' do
|
|
|
24
24
|
expect(response).to have_http_status(:found)
|
|
25
25
|
end
|
|
26
26
|
else
|
|
27
|
-
it 'responds with
|
|
28
|
-
expect(response).to have_http_status(:ok)
|
|
27
|
+
it 'responds with the configured status code' do
|
|
28
|
+
expect(response).to have_http_status(check_status(:destroy) || :ok)
|
|
29
29
|
end
|
|
30
30
|
end
|
|
31
31
|
end
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
RSpec.shared_examples 'simple crud for edit' do
|
|
4
4
|
describe 'GET #edit' do
|
|
5
|
-
subject(:edit_request) { get :edit, params: with_route_params(edit_params), format:
|
|
5
|
+
subject(:edit_request) { get :edit, params: with_route_params(edit_params), format: format_param(:edit) }
|
|
6
6
|
|
|
7
7
|
before do
|
|
8
8
|
model
|
|
@@ -10,7 +10,7 @@ RSpec.shared_examples 'simple crud for edit' do
|
|
|
10
10
|
|
|
11
11
|
context 'without authenticated user' do
|
|
12
12
|
subject!(:req) do
|
|
13
|
-
get :edit, params: with_route_params(record_param(:edit, model)), format:
|
|
13
|
+
get :edit, params: with_route_params(record_param(:edit, model)), format: format_param(:edit)
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
include_examples 'unauthorized when not logged in' if check_authenticate(:edit)
|
|
@@ -14,7 +14,7 @@ RSpec.shared_examples 'simple crud for index' do
|
|
|
14
14
|
|
|
15
15
|
before do
|
|
16
16
|
make_policies_succeed(:index) if check_authorize(:index)
|
|
17
|
-
get :index, params: with_route_params({}), format:
|
|
17
|
+
get :index, params: with_route_params({}), format: format_param(:index)
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
if check_html(:index)
|
|
@@ -25,7 +25,7 @@ RSpec.shared_examples 'simple crud for index' do
|
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
it 'renders the correct paginated models' do
|
|
28
|
-
expect(response_body['page'].map { |a| a['id'] }).to
|
|
28
|
+
expect(response_body['page'].map { |a| a['id'] }).to match_array(model_class_object.all.map(&:id))
|
|
29
29
|
end
|
|
30
30
|
else
|
|
31
31
|
it 'renders unpaginated models correctly serialized' do
|
|
@@ -33,7 +33,7 @@ RSpec.shared_examples 'simple crud for index' do
|
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
it 'renders the correct unpaginated models' do
|
|
36
|
-
expect(response_body.map { |a| a['id'] }).to
|
|
36
|
+
expect(response_body.map { |a| a['id'] }).to match_array(model_class_object.all.map(&:id))
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
end
|
|
@@ -8,7 +8,7 @@ RSpec.shared_examples 'simple crud for index with block' do
|
|
|
8
8
|
|
|
9
9
|
before do
|
|
10
10
|
created_models
|
|
11
|
-
get :index, params: with_route_params({}), format:
|
|
11
|
+
get :index, params: with_route_params({}), format: format_param(:index)
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
if check_html(:index)
|
|
@@ -13,7 +13,7 @@ RSpec.shared_examples 'simple crud for index with scope' do
|
|
|
13
13
|
make_policies_succeed(:index) if check_authorize(:index)
|
|
14
14
|
my_models
|
|
15
15
|
other_models
|
|
16
|
-
get :index, params: with_route_params(request_params), format:
|
|
16
|
+
get :index, params: with_route_params(request_params), format: format_param(:index)
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
if check_html(:index)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# For a parent: controller. The parent in route_params must match the record's owner_association.
|
|
4
|
+
RSpec.shared_examples 'simple crud for nested resource' do
|
|
5
|
+
describe 'parent: scoping' do
|
|
6
|
+
include_context 'with authenticated user' if check_authenticate(:show)
|
|
7
|
+
|
|
8
|
+
it 'finds a record inside the parent' do
|
|
9
|
+
get :show, params: with_route_params(record_param(:show, model)), format: format_param(:show)
|
|
10
|
+
|
|
11
|
+
expect(response).to have_http_status(:ok)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it 'returns not found for a record outside the parent' do
|
|
15
|
+
outside = create_record(model_class, model_attributes.merge(owner_association => other_user))
|
|
16
|
+
get :show, params: with_route_params(record_param(:show, outside)), format: format_param(:show)
|
|
17
|
+
|
|
18
|
+
expect(response).to have_http_status(:not_found)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -10,7 +10,7 @@ RSpec.shared_examples 'simple crud for new' do
|
|
|
10
10
|
|
|
11
11
|
before do
|
|
12
12
|
make_policies_succeed(:new) if check_authorize(:new)
|
|
13
|
-
get :new, params: with_route_params({}), format:
|
|
13
|
+
get :new, params: with_route_params({}), format: format_param(:new)
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
it 'responds with ok status' do
|
|
@@ -6,7 +6,7 @@ RSpec.shared_examples 'simple crud for new with block' do
|
|
|
6
6
|
|
|
7
7
|
before do
|
|
8
8
|
make_policies_succeed(:new) if check_authorize(:new)
|
|
9
|
-
get :new, params: with_route_params({}), format:
|
|
9
|
+
get :new, params: with_route_params({}), format: format_param(:new)
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
if check_html(:new)
|
|
@@ -5,7 +5,7 @@ RSpec.shared_examples 'simple crud for new with build' do
|
|
|
5
5
|
include_context 'with authenticated user' if check_authenticate(:new)
|
|
6
6
|
|
|
7
7
|
before do
|
|
8
|
-
get :new, params: with_route_params({}), format:
|
|
8
|
+
get :new, params: with_route_params({}), format: format_param(:new)
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
it 'builds the record owned by the current user', :aggregate_failures do
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Include alongside the per-action examples for a controller using owned_by:.
|
|
4
|
+
RSpec.shared_examples 'simple crud for owned resource' do
|
|
5
|
+
describe 'owned_by: scoping' do
|
|
6
|
+
include_context 'with authenticated user'
|
|
7
|
+
|
|
8
|
+
let!(:someone_elses_model) do
|
|
9
|
+
create_record(model_class, model_attributes.merge(owner_association => other_user))
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it 'returns not found for a record owned by another user' do
|
|
13
|
+
get :show, params: with_route_params(record_param(:show, someone_elses_model)), format: format_param(:show)
|
|
14
|
+
|
|
15
|
+
expect(response).to have_http_status(:not_found)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'ignores an attempt to update a record owned by another user', :aggregate_failures do
|
|
19
|
+
params = with_route_params(record_param(:update, someone_elses_model)).merge(body_params(model_params))
|
|
20
|
+
patch :update, params: params, format: format_param(:update)
|
|
21
|
+
|
|
22
|
+
expect(response).to have_http_status(:not_found)
|
|
23
|
+
expect(someone_elses_model.reload.public_send(required_attribute))
|
|
24
|
+
.not_to eq(model_params[required_attribute])
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it 'attributes a created record to the current user regardless of the request', :aggregate_failures do
|
|
28
|
+
body = body_params(model_params.merge(owner_association => other_user.id))
|
|
29
|
+
post :create, params: with_route_params(body), format: format_param(:create)
|
|
30
|
+
|
|
31
|
+
expect(response).to have_http_status(check_status(:create) || :created)
|
|
32
|
+
expect(model_class_object.last.public_send(owner_association)).to eq(current_user)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
RSpec.shared_examples 'simple crud for show' do
|
|
4
4
|
describe 'GET #show' do
|
|
5
|
-
subject(:show_request) { get :show, params: with_route_params(show_params), format:
|
|
5
|
+
subject(:show_request) { get :show, params: with_route_params(show_params), format: format_param(:show) }
|
|
6
6
|
|
|
7
7
|
before do
|
|
8
8
|
model
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
context 'without authenticated user' do
|
|
12
|
-
subject!(:req) { get :show, params: with_route_params(record_param(:show, model)), format:
|
|
12
|
+
subject!(:req) { get :show, params: with_route_params(record_param(:show, model)), format: format_param(:show) }
|
|
13
13
|
|
|
14
14
|
include_examples 'unauthorized when not logged in' if check_authenticate(:show)
|
|
15
15
|
end
|
|
@@ -8,7 +8,7 @@ RSpec.shared_examples 'simple crud for show with block' do
|
|
|
8
8
|
|
|
9
9
|
before do
|
|
10
10
|
make_policies_succeed(:show) if check_authorize(:show)
|
|
11
|
-
get :show, params: with_route_params(record_param(:show, record)), format:
|
|
11
|
+
get :show, params: with_route_params(record_param(:show, record)), format: format_param(:show)
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
if check_html(:show)
|
|
@@ -8,7 +8,7 @@ RSpec.shared_examples 'simple crud for show with finder' do
|
|
|
8
8
|
before do
|
|
9
9
|
model
|
|
10
10
|
get :show, params: with_route_params(finder_key => model.public_send(finder_key)),
|
|
11
|
-
format:
|
|
11
|
+
format: format_param(:show)
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
if check_block(:show)
|
|
@@ -5,7 +5,7 @@ RSpec.shared_examples 'simple crud for update' do
|
|
|
5
5
|
context 'without authenticated user' do
|
|
6
6
|
subject!(:req) do
|
|
7
7
|
update_params = body_params(params_for(model_class)).merge(record_param(:update, model))
|
|
8
|
-
put :update, params: with_route_params(update_params), format:
|
|
8
|
+
put :update, params: with_route_params(update_params), format: format_param(:update)
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
include_examples 'unauthorized when not logged in' if check_authenticate(:update)
|
|
@@ -18,7 +18,7 @@ RSpec.shared_examples 'simple crud for update' do
|
|
|
18
18
|
before do
|
|
19
19
|
make_policies_fail(:update)
|
|
20
20
|
put :update, params: with_route_params(body_params(model_params).merge(record_param(:update, model))),
|
|
21
|
-
format:
|
|
21
|
+
format: format_param(:update)
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
it 'fails with forbidden' do
|
|
@@ -34,7 +34,7 @@ RSpec.shared_examples 'simple crud for update' do
|
|
|
34
34
|
|
|
35
35
|
before do
|
|
36
36
|
model
|
|
37
|
-
put :update, params: with_route_params(update_params), format:
|
|
37
|
+
put :update, params: with_route_params(update_params), format: format_param(:update)
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
if check_html(:update)
|
|
@@ -42,8 +42,8 @@ RSpec.shared_examples 'simple crud for update' do
|
|
|
42
42
|
expect(response).to have_http_status(:found)
|
|
43
43
|
end
|
|
44
44
|
else
|
|
45
|
-
it 'response with
|
|
46
|
-
expect(response).to have_http_status(:ok)
|
|
45
|
+
it 'response with the configured status code' do
|
|
46
|
+
expect(response).to have_http_status(check_status(:update) || :ok)
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
it 'updates an model' do
|
|
@@ -66,7 +66,7 @@ RSpec.shared_examples 'simple crud for update' do
|
|
|
66
66
|
|
|
67
67
|
before do
|
|
68
68
|
put :update, params: with_route_params(record_param(:update, nil, not_found: true)),
|
|
69
|
-
format:
|
|
69
|
+
format: format_param(:update)
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
it 'response with 404 status code' do
|
|
@@ -86,7 +86,7 @@ RSpec.shared_examples 'simple crud for update' do
|
|
|
86
86
|
model
|
|
87
87
|
put :update, params: with_route_params(body_params({ required_attribute => nil }.merge(owner_params))
|
|
88
88
|
.merge(record_param(:update, model))),
|
|
89
|
-
format:
|
|
89
|
+
format: format_param(:update)
|
|
90
90
|
end
|
|
91
91
|
|
|
92
92
|
unless check_block(:update)
|
|
@@ -12,7 +12,7 @@ RSpec.shared_examples 'simple crud for update with finder' do
|
|
|
12
12
|
|
|
13
13
|
before do
|
|
14
14
|
model
|
|
15
|
-
put :update, params: update_params, format:
|
|
15
|
+
put :update, params: update_params, format: format_param(:update)
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
it 'updates the model' do
|
|
@@ -4,7 +4,7 @@ RSpec.shared_examples 'simple crud not found with finder' do |http_method, actio
|
|
|
4
4
|
context 'when the model does not exist' do
|
|
5
5
|
before do
|
|
6
6
|
send(http_method, action, params: with_route_params(finder_key => "nonexistent-#{finder_key}"),
|
|
7
|
-
format:
|
|
7
|
+
format: format_param(action))
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
it 'responds with not found status' do
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe Blueprint::DummyModelsController, type: :controller do
|
|
6
|
+
let(:serializer) { DummyModelBlueprint }
|
|
7
|
+
|
|
8
|
+
include_examples 'simple crud for index'
|
|
9
|
+
include_examples 'simple crud for show'
|
|
10
|
+
include_examples 'simple crud for create'
|
|
11
|
+
include_examples 'simple crud for update'
|
|
12
|
+
include_examples 'simple crud for destroy'
|
|
13
|
+
|
|
14
|
+
describe 'GET #show' do
|
|
15
|
+
include_context 'with authenticated user'
|
|
16
|
+
|
|
17
|
+
let!(:record) { create(:dummy_model, user: current_user) }
|
|
18
|
+
|
|
19
|
+
it 'passes serializer_options to the blueprint' do
|
|
20
|
+
get :show, params: { id: record.id }
|
|
21
|
+
|
|
22
|
+
expect(response.parsed_body['url']).to eq(dummy_model_url(record))
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|