cuprum-rails 0.1.0 → 0.2.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 +145 -0
- data/DEVELOPMENT.md +20 -0
- data/README.md +356 -63
- data/lib/cuprum/rails/action.rb +32 -16
- data/lib/cuprum/rails/actions/create.rb +62 -15
- data/lib/cuprum/rails/actions/destroy.rb +23 -7
- data/lib/cuprum/rails/actions/edit.rb +23 -7
- data/lib/cuprum/rails/actions/index.rb +30 -10
- data/lib/cuprum/rails/actions/middleware/associations/cache.rb +112 -0
- data/lib/cuprum/rails/actions/middleware/associations/find.rb +23 -0
- data/lib/cuprum/rails/actions/middleware/associations/parent.rb +70 -0
- data/lib/cuprum/rails/actions/middleware/associations/query.rb +140 -0
- data/lib/cuprum/rails/actions/middleware/associations.rb +12 -0
- data/lib/cuprum/rails/actions/middleware/log_request.rb +126 -0
- data/lib/cuprum/rails/actions/middleware/log_result.rb +51 -0
- data/lib/cuprum/rails/actions/middleware/resources/find.rb +44 -0
- data/lib/cuprum/rails/actions/middleware/resources/query.rb +91 -0
- data/lib/cuprum/rails/actions/middleware/resources.rb +11 -0
- data/lib/cuprum/rails/actions/middleware.rb +13 -0
- data/lib/cuprum/rails/actions/new.rb +16 -4
- data/lib/cuprum/rails/actions/parameter_validation.rb +60 -0
- data/lib/cuprum/rails/actions/resource_action.rb +119 -42
- data/lib/cuprum/rails/actions/show.rb +23 -7
- data/lib/cuprum/rails/actions/update.rb +70 -22
- data/lib/cuprum/rails/actions.rb +11 -7
- data/lib/cuprum/rails/collection.rb +27 -47
- data/lib/cuprum/rails/command.rb +3 -1
- data/lib/cuprum/rails/commands/destroy_one.rb +10 -6
- data/lib/cuprum/rails/commands/find_many.rb +8 -1
- data/lib/cuprum/rails/commands/find_matching.rb +1 -1
- data/lib/cuprum/rails/commands/find_one.rb +8 -0
- data/lib/cuprum/rails/commands/insert_one.rb +17 -6
- data/lib/cuprum/rails/commands/update_one.rb +16 -5
- data/lib/cuprum/rails/constraints/parameters_contract.rb +14 -0
- data/lib/cuprum/rails/constraints.rb +10 -0
- data/lib/cuprum/rails/controller.rb +12 -2
- data/lib/cuprum/rails/controllers/action.rb +100 -0
- data/lib/cuprum/rails/controllers/class_methods/actions.rb +33 -7
- data/lib/cuprum/rails/controllers/class_methods/configuration.rb +36 -0
- data/lib/cuprum/rails/controllers/class_methods/middleware.rb +88 -0
- data/lib/cuprum/rails/controllers/class_methods/validations.rb +2 -2
- data/lib/cuprum/rails/controllers/configuration.rb +41 -1
- data/lib/cuprum/rails/controllers/middleware.rb +59 -0
- data/lib/cuprum/rails/controllers.rb +2 -0
- data/lib/cuprum/rails/errors/invalid_parameters.rb +55 -0
- data/lib/cuprum/rails/errors/invalid_statement.rb +11 -0
- data/lib/cuprum/rails/errors/missing_parameter.rb +42 -0
- data/lib/cuprum/rails/errors/resource_error.rb +46 -0
- data/lib/cuprum/rails/errors.rb +6 -1
- data/lib/cuprum/rails/map_errors.rb +29 -1
- data/lib/cuprum/rails/query.rb +1 -1
- data/lib/cuprum/rails/repository.rb +12 -25
- data/lib/cuprum/rails/request.rb +149 -60
- data/lib/cuprum/rails/resource.rb +119 -85
- data/lib/cuprum/rails/responders/base_responder.rb +78 -0
- data/lib/cuprum/rails/responders/html/plural_resource.rb +9 -39
- data/lib/cuprum/rails/responders/html/rendering.rb +81 -0
- data/lib/cuprum/rails/responders/html/resource.rb +107 -0
- data/lib/cuprum/rails/responders/html/singular_resource.rb +9 -38
- data/lib/cuprum/rails/responders/html.rb +2 -0
- data/lib/cuprum/rails/responders/html_responder.rb +8 -52
- data/lib/cuprum/rails/responders/json/resource.rb +3 -3
- data/lib/cuprum/rails/responders/json_responder.rb +31 -16
- data/lib/cuprum/rails/responders/matching.rb +29 -27
- data/lib/cuprum/rails/responders/serialization.rb +11 -9
- data/lib/cuprum/rails/responders.rb +1 -0
- data/lib/cuprum/rails/responses/head_response.rb +24 -0
- data/lib/cuprum/rails/responses/html/redirect_back_response.rb +55 -0
- data/lib/cuprum/rails/responses/html/redirect_response.rb +19 -4
- data/lib/cuprum/rails/responses/html/render_response.rb +17 -5
- data/lib/cuprum/rails/responses/html.rb +6 -2
- data/lib/cuprum/rails/responses.rb +1 -0
- data/lib/cuprum/rails/result.rb +36 -0
- data/lib/cuprum/rails/routes.rb +36 -23
- data/lib/cuprum/rails/rspec/contract_helpers.rb +57 -0
- data/lib/cuprum/rails/rspec/contracts/action_contracts.rb +754 -0
- data/lib/cuprum/rails/rspec/contracts/actions/create_contracts.rb +289 -0
- data/lib/cuprum/rails/rspec/contracts/actions/destroy_contracts.rb +164 -0
- data/lib/cuprum/rails/rspec/contracts/actions/edit_contracts.rb +73 -0
- data/lib/cuprum/rails/rspec/contracts/actions/index_contracts.rb +108 -0
- data/lib/cuprum/rails/rspec/contracts/actions/new_contracts.rb +111 -0
- data/lib/cuprum/rails/rspec/contracts/actions/show_contracts.rb +72 -0
- data/lib/cuprum/rails/rspec/contracts/actions/update_contracts.rb +263 -0
- data/lib/cuprum/rails/rspec/contracts/actions.rb +8 -0
- data/lib/cuprum/rails/rspec/contracts/command_contracts.rb +479 -0
- data/lib/cuprum/rails/rspec/contracts/responder_contracts.rb +232 -0
- data/lib/cuprum/rails/rspec/contracts/routes_contracts.rb +363 -0
- data/lib/cuprum/rails/rspec/contracts/serializers_contracts.rb +70 -0
- data/lib/cuprum/rails/rspec/contracts.rb +8 -0
- data/lib/cuprum/rails/rspec/matchers/be_a_result_matcher.rb +64 -0
- data/lib/cuprum/rails/rspec/matchers.rb +41 -0
- data/lib/cuprum/rails/serializers/base_serializer.rb +60 -0
- data/lib/cuprum/rails/serializers/context.rb +84 -0
- data/lib/cuprum/rails/serializers/json/active_record_serializer.rb +2 -2
- data/lib/cuprum/rails/serializers/json/array_serializer.rb +9 -8
- data/lib/cuprum/rails/serializers/json/attributes_serializer.rb +95 -172
- data/lib/cuprum/rails/serializers/json/error_serializer.rb +2 -2
- data/lib/cuprum/rails/serializers/json/hash_serializer.rb +9 -8
- data/lib/cuprum/rails/serializers/json/identity_serializer.rb +3 -3
- data/lib/cuprum/rails/serializers/json/properties_serializer.rb +252 -0
- data/lib/cuprum/rails/serializers/json.rb +2 -1
- data/lib/cuprum/rails/serializers.rb +3 -1
- data/lib/cuprum/rails/version.rb +1 -1
- data/lib/cuprum/rails.rb +19 -16
- metadata +73 -131
- data/lib/cuprum/rails/controller_action.rb +0 -121
- data/lib/cuprum/rails/errors/missing_parameters.rb +0 -33
- data/lib/cuprum/rails/errors/missing_primary_key.rb +0 -46
- data/lib/cuprum/rails/errors/undefined_permitted_attributes.rb +0 -34
- data/lib/cuprum/rails/rspec/command_contract.rb +0 -460
- data/lib/cuprum/rails/rspec/define_route_contract.rb +0 -84
- data/lib/cuprum/rails/serializers/json/serializer.rb +0 -66
@@ -10,15 +10,10 @@ module Cuprum::Rails::Actions
|
|
10
10
|
class Update < Cuprum::Rails::Actions::ResourceAction
|
11
11
|
private
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
entity
|
17
|
-
collection.find_one.call(primary_key: primary_key)
|
18
|
-
end
|
19
|
-
step do
|
20
|
-
collection.assign_one.call(attributes: attributes, entity: entity)
|
21
|
-
end
|
13
|
+
attr_reader :entity
|
14
|
+
|
15
|
+
def build_response
|
16
|
+
{ resource.singular_name => entity }
|
22
17
|
end
|
23
18
|
|
24
19
|
def failed_validation?(result)
|
@@ -26,34 +21,87 @@ module Cuprum::Rails::Actions
|
|
26
21
|
result.error.is_a?(Cuprum::Collections::Errors::FailedValidation)
|
27
22
|
end
|
28
23
|
|
29
|
-
def
|
30
|
-
|
24
|
+
def find_entity(primary_key:)
|
25
|
+
collection.find_one.call(primary_key: primary_key)
|
26
|
+
end
|
27
|
+
|
28
|
+
def find_required_entities
|
29
|
+
@entity = step { find_entity(primary_key: resource_id) }
|
30
|
+
end
|
31
31
|
|
32
|
-
|
32
|
+
def handle_failed_validation
|
33
|
+
result = yield
|
33
34
|
|
34
35
|
return result unless failed_validation?(result)
|
35
36
|
|
36
37
|
Cuprum::Result.new(
|
37
|
-
error: result.error,
|
38
|
+
error: scope_validation_errors(result.error),
|
38
39
|
status: :failure,
|
39
|
-
value: {
|
40
|
+
value: { resource.singular_name => entity }
|
40
41
|
)
|
41
42
|
end
|
42
43
|
|
43
|
-
def
|
44
|
-
|
44
|
+
def parameters_contract
|
45
|
+
return @parameters_contract if @parameters_contract
|
45
46
|
|
46
|
-
|
47
|
-
|
47
|
+
resource_name = resource.singular_name
|
48
|
+
parameters_constraint = require_parameters_constraint
|
48
49
|
|
49
|
-
|
50
|
+
@parameters_contract =
|
51
|
+
Cuprum::Rails::Constraints::ParametersContract.new do
|
52
|
+
key 'id', Stannum::Constraints::Presence.new
|
53
|
+
key resource_name, parameters_constraint
|
54
|
+
end
|
55
|
+
end
|
50
56
|
|
51
|
-
|
57
|
+
def perform_action
|
58
|
+
handle_failed_validation do
|
59
|
+
update_entity(attributes: resource_params)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def process(**)
|
64
|
+
@entity = nil
|
65
|
+
|
66
|
+
super
|
67
|
+
end
|
68
|
+
|
69
|
+
def require_parameters_constraint
|
70
|
+
Stannum::Contract.new do
|
71
|
+
constraint Stannum::Constraints::Presence.new, sanity: true
|
72
|
+
constraint Stannum::Constraints::Types::HashType.new
|
73
|
+
end
|
74
|
+
end
|
52
75
|
|
53
|
-
|
76
|
+
def require_permitted_attributes?
|
77
|
+
true
|
78
|
+
end
|
79
|
+
|
80
|
+
def scope_validation_errors(error)
|
81
|
+
mapped_errors = Stannum::Errors.new
|
82
|
+
|
83
|
+
error.errors.each do |err|
|
84
|
+
mapped_errors
|
85
|
+
.dig(resource.singular_name, *err[:path].map(&:to_s))
|
86
|
+
.add(err[:type], message: err[:message], **err[:data])
|
54
87
|
end
|
55
88
|
|
56
|
-
|
89
|
+
Cuprum::Collections::Errors::FailedValidation.new(
|
90
|
+
entity_class: error.entity_class,
|
91
|
+
errors: mapped_errors
|
92
|
+
)
|
93
|
+
end
|
94
|
+
|
95
|
+
def update_entity(attributes:)
|
96
|
+
steps do
|
97
|
+
step do
|
98
|
+
collection.assign_one.call(attributes: attributes, entity: entity)
|
99
|
+
end
|
100
|
+
|
101
|
+
step { collection.validate_one.call(entity: entity) }
|
102
|
+
|
103
|
+
step { collection.update_one.call(entity: entity) }
|
104
|
+
end
|
57
105
|
end
|
58
106
|
end
|
59
107
|
end
|
data/lib/cuprum/rails/actions.rb
CHANGED
@@ -5,12 +5,16 @@ require 'cuprum/rails'
|
|
5
5
|
module Cuprum::Rails
|
6
6
|
# Namespace for defined resourceful actions.
|
7
7
|
module Actions
|
8
|
-
autoload :Create,
|
9
|
-
autoload :Destroy,
|
10
|
-
autoload :Edit,
|
11
|
-
autoload :Index,
|
12
|
-
autoload :
|
13
|
-
autoload :
|
14
|
-
autoload :
|
8
|
+
autoload :Create, 'cuprum/rails/actions/create'
|
9
|
+
autoload :Destroy, 'cuprum/rails/actions/destroy'
|
10
|
+
autoload :Edit, 'cuprum/rails/actions/edit'
|
11
|
+
autoload :Index, 'cuprum/rails/actions/index'
|
12
|
+
autoload :Middleware, 'cuprum/rails/actions/middleware'
|
13
|
+
autoload :New, 'cuprum/rails/actions/new'
|
14
|
+
autoload :ParameterValidation, 'cuprum/rails/actions/parameter_validation'
|
15
|
+
autoload :ResourceAction, 'cuprum/rails/actions/resource_action'
|
16
|
+
autoload :ResourceMethods, 'cuprum/rails/actions/resource_methods'
|
17
|
+
autoload :Show, 'cuprum/rails/actions/show'
|
18
|
+
autoload :Update, 'cuprum/rails/actions/update'
|
15
19
|
end
|
16
20
|
end
|
@@ -1,42 +1,31 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'cuprum/collections/collection'
|
3
4
|
require 'cuprum/command_factory'
|
4
5
|
|
5
6
|
require 'cuprum/rails'
|
6
7
|
|
7
8
|
module Cuprum::Rails
|
8
9
|
# Wraps an ActiveRecord model as a Cuprum collection.
|
9
|
-
class Collection < Cuprum::
|
10
|
-
# @
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
10
|
+
class Collection < Cuprum::Collections::Collection
|
11
|
+
# @overload initialize(entity_class: nil, name: nil, qualified_name: nil, singular_name: nil, **options)
|
12
|
+
# @param entity_class [Class, String] the class of entity represented by
|
13
|
+
# the collection.
|
14
|
+
# @param name [String] the name of the collection.
|
15
|
+
# @param qualified_name [String] a scoped name for the collection.
|
16
|
+
# @param singular_name [String] the name of an entity in the collection.
|
17
|
+
# @param options [Hash] additional options for the collection.
|
18
|
+
#
|
19
|
+
# @option options primary_key_name [String] the name of the primary key
|
20
|
+
# attribute. Defaults to 'id'.
|
21
|
+
# @option primary_key_type [Class, Stannum::Constraint] the type of
|
22
|
+
# the primary key attribute. Defaults to Integer.
|
23
|
+
def initialize(**params)
|
24
|
+
params = disambiguate_keyword(params, :entity_class, :record_class)
|
25
|
+
|
26
|
+
super(**params)
|
26
27
|
end
|
27
28
|
|
28
|
-
# @return [String] The name of the collection.
|
29
|
-
attr_reader :collection_name
|
30
|
-
|
31
|
-
# @return [String] the name of a collection entity.
|
32
|
-
attr_reader :member_name
|
33
|
-
|
34
|
-
# @return [Hash<Symbol>] additional options for the command.
|
35
|
-
attr_reader :options
|
36
|
-
|
37
|
-
# @return [Class] the ActiveRecord class for the collection.
|
38
|
-
attr_reader :record_class
|
39
|
-
|
40
29
|
command_class :assign_one do
|
41
30
|
Cuprum::Rails::Commands::AssignOne
|
42
31
|
.subclass(**command_options)
|
@@ -86,30 +75,21 @@ module Cuprum::Rails
|
|
86
75
|
#
|
87
76
|
# @return [Cuprum::Rails::Query] the query.
|
88
77
|
def query
|
89
|
-
Cuprum::Rails::Query.new(
|
90
|
-
end
|
91
|
-
|
92
|
-
private
|
93
|
-
|
94
|
-
def command_options
|
95
|
-
@command_options ||= {
|
96
|
-
collection_name: collection_name,
|
97
|
-
member_name: member_name,
|
98
|
-
record_class: record_class,
|
99
|
-
**options
|
100
|
-
}
|
78
|
+
Cuprum::Rails::Query.new(entity_class)
|
101
79
|
end
|
102
80
|
|
103
|
-
|
104
|
-
|
81
|
+
# @return [Class] the class of entity represented by the collection.
|
82
|
+
def record_class
|
83
|
+
tools.core_tools.deprecate '#record_class method',
|
84
|
+
message: 'Use #entity_class instead'
|
105
85
|
|
106
|
-
|
86
|
+
entity_class
|
107
87
|
end
|
108
88
|
|
109
|
-
|
110
|
-
return member_name.to_s unless member_name.nil?
|
89
|
+
private
|
111
90
|
|
112
|
-
|
91
|
+
def command_options
|
92
|
+
super().merge(record_class: entity_class)
|
113
93
|
end
|
114
94
|
end
|
115
95
|
end
|
data/lib/cuprum/rails/command.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'cuprum/collections'
|
4
|
+
|
3
5
|
require 'cuprum/rails'
|
4
6
|
|
5
7
|
module Cuprum::Rails
|
@@ -46,7 +48,7 @@ module Cuprum::Rails
|
|
46
48
|
|
47
49
|
# @return [Symbol] the name of the primary key attribute.
|
48
50
|
def primary_key_name
|
49
|
-
@primary_key_name ||= record_class.primary_key
|
51
|
+
@primary_key_name ||= record_class.primary_key
|
50
52
|
end
|
51
53
|
|
52
54
|
# @return [Class] the type of the primary key attribute.
|
@@ -25,6 +25,15 @@ module Cuprum::Rails::Commands
|
|
25
25
|
|
26
26
|
private
|
27
27
|
|
28
|
+
def not_found_error(primary_key)
|
29
|
+
Cuprum::Collections::Errors::NotFound.new(
|
30
|
+
attribute_name: primary_key_name,
|
31
|
+
attribute_value: primary_key,
|
32
|
+
collection_name: collection_name,
|
33
|
+
primary_key: true
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
28
37
|
def process(primary_key:)
|
29
38
|
step { validate_primary_key(primary_key) }
|
30
39
|
|
@@ -32,12 +41,7 @@ module Cuprum::Rails::Commands
|
|
32
41
|
|
33
42
|
entity.destroy
|
34
43
|
rescue ActiveRecord::RecordNotFound
|
35
|
-
|
36
|
-
collection_name: collection_name,
|
37
|
-
primary_key_name: primary_key_name,
|
38
|
-
primary_key_values: [primary_key]
|
39
|
-
)
|
40
|
-
Cuprum::Result.new(error: error)
|
44
|
+
Cuprum::Result.new(error: not_found_error(primary_key))
|
41
45
|
end
|
42
46
|
end
|
43
47
|
end
|
@@ -6,13 +6,14 @@ require 'cuprum/collections/commands/abstract_find_many'
|
|
6
6
|
|
7
7
|
require 'cuprum/rails/command'
|
8
8
|
require 'cuprum/rails/commands'
|
9
|
+
require 'cuprum/rails/errors/invalid_statement'
|
9
10
|
|
10
11
|
module Cuprum::Rails::Commands
|
11
12
|
# Command for finding multiple ActiveRecord records by primary key.
|
12
13
|
class FindMany < Cuprum::Rails::Command
|
13
14
|
include Cuprum::Collections::Commands::AbstractFindMany
|
14
15
|
|
15
|
-
# @!method call(primary_keys:, allow_partial: false, envelope: false, scope: nil)
|
16
|
+
# @!method call(primary_keys:, allow_partial: false, envelope: false, scope: nil)
|
16
17
|
# Queries the collection for the records with the given primary keys.
|
17
18
|
#
|
18
19
|
# The command will find and return the entities with the given primary
|
@@ -46,6 +47,10 @@ module Cuprum::Rails::Commands
|
|
46
47
|
Cuprum::Rails::Query.new(record_class)
|
47
48
|
end
|
48
49
|
|
50
|
+
def invalid_statement_error(message)
|
51
|
+
Cuprum::Rails::Errors::InvalidStatement.new(message: message)
|
52
|
+
end
|
53
|
+
|
49
54
|
def process(
|
50
55
|
primary_keys:,
|
51
56
|
allow_partial: false,
|
@@ -55,6 +60,8 @@ module Cuprum::Rails::Commands
|
|
55
60
|
step { validate_primary_keys(primary_keys) }
|
56
61
|
|
57
62
|
super
|
63
|
+
rescue ActiveRecord::StatementInvalid => exception
|
64
|
+
failure(invalid_statement_error(exception.message))
|
58
65
|
end
|
59
66
|
end
|
60
67
|
end
|
@@ -12,7 +12,7 @@ module Cuprum::Rails::Commands
|
|
12
12
|
class FindMatching < Cuprum::Rails::Command
|
13
13
|
include Cuprum::Collections::Commands::AbstractFindMatching
|
14
14
|
|
15
|
-
# @!method call(envelope: false, limit: nil, offset: nil, order: nil, scope: nil, where: nil, &block)
|
15
|
+
# @!method call(envelope: false, limit: nil, offset: nil, order: nil, scope: nil, where: nil, &block)
|
16
16
|
# Queries the collection for records matching the given conditions.
|
17
17
|
#
|
18
18
|
# @param envelope [Boolean] If true, wraps the result value in a Hash.
|
@@ -1,11 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'stannum/constraints/boolean'
|
4
|
+
require 'stannum/errors'
|
4
5
|
|
5
6
|
require 'cuprum/collections/commands/abstract_find_one'
|
6
7
|
|
7
8
|
require 'cuprum/rails/command'
|
8
9
|
require 'cuprum/rails/commands'
|
10
|
+
require 'cuprum/rails/errors/invalid_statement'
|
9
11
|
|
10
12
|
module Cuprum::Rails::Commands
|
11
13
|
# Command for finding one ActiveRecord record by primary key.
|
@@ -41,10 +43,16 @@ module Cuprum::Rails::Commands
|
|
41
43
|
Cuprum::Rails::Query.new(record_class)
|
42
44
|
end
|
43
45
|
|
46
|
+
def invalid_statement_error(message)
|
47
|
+
Cuprum::Rails::Errors::InvalidStatement.new(message: message)
|
48
|
+
end
|
49
|
+
|
44
50
|
def process(primary_key:, envelope: false, scope: nil)
|
45
51
|
step { validate_primary_key(primary_key) }
|
46
52
|
|
47
53
|
super
|
54
|
+
rescue ActiveRecord::StatementInvalid => exception
|
55
|
+
failure(invalid_statement_error(exception.message))
|
48
56
|
end
|
49
57
|
end
|
50
58
|
end
|
@@ -4,6 +4,7 @@ require 'cuprum/collections/errors/already_exists'
|
|
4
4
|
|
5
5
|
require 'cuprum/rails/command'
|
6
6
|
require 'cuprum/rails/commands'
|
7
|
+
require 'cuprum/rails/errors/invalid_statement'
|
7
8
|
|
8
9
|
module Cuprum::Rails::Commands
|
9
10
|
# Command for inserting an ActiveRecord record into the collection.
|
@@ -23,6 +24,19 @@ module Cuprum::Rails::Commands
|
|
23
24
|
|
24
25
|
private
|
25
26
|
|
27
|
+
def already_exists_error(primary_key)
|
28
|
+
Cuprum::Collections::Errors::AlreadyExists.new(
|
29
|
+
attribute_name: primary_key_name,
|
30
|
+
attribute_value: primary_key,
|
31
|
+
collection_name: collection_name,
|
32
|
+
primary_key: true
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
def invalid_statement_error(message)
|
37
|
+
Cuprum::Rails::Errors::InvalidStatement.new(message: message)
|
38
|
+
end
|
39
|
+
|
26
40
|
def process(entity:)
|
27
41
|
step { validate_entity(entity) }
|
28
42
|
|
@@ -30,12 +44,9 @@ module Cuprum::Rails::Commands
|
|
30
44
|
|
31
45
|
entity
|
32
46
|
rescue ActiveRecord::RecordNotUnique
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
primary_key_values: entity[primary_key_name]
|
37
|
-
)
|
38
|
-
failure(error)
|
47
|
+
failure(already_exists_error(entity[primary_key_name]))
|
48
|
+
rescue ActiveRecord::StatementInvalid => exception
|
49
|
+
failure(invalid_statement_error(exception.message))
|
39
50
|
end
|
40
51
|
end
|
41
52
|
end
|
@@ -4,6 +4,7 @@ require 'cuprum/collections/errors/not_found'
|
|
4
4
|
|
5
5
|
require 'cuprum/rails/command'
|
6
6
|
require 'cuprum/rails/commands'
|
7
|
+
require 'cuprum/rails/errors/invalid_statement'
|
7
8
|
|
8
9
|
module Cuprum::Rails::Commands
|
9
10
|
# Command for updating an ActiveRecord record in the collection.
|
@@ -28,12 +29,20 @@ module Cuprum::Rails::Commands
|
|
28
29
|
|
29
30
|
return if query.exists?
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
32
|
+
failure(not_found_error(primary_key))
|
33
|
+
end
|
34
|
+
|
35
|
+
def invalid_statement_error(message)
|
36
|
+
Cuprum::Rails::Errors::InvalidStatement.new(message: message)
|
37
|
+
end
|
38
|
+
|
39
|
+
def not_found_error(primary_key)
|
40
|
+
Cuprum::Collections::Errors::NotFound.new(
|
41
|
+
attribute_name: primary_key_name,
|
42
|
+
attribute_value: primary_key,
|
43
|
+
collection_name: collection_name,
|
44
|
+
primary_key: true
|
35
45
|
)
|
36
|
-
failure(error)
|
37
46
|
end
|
38
47
|
|
39
48
|
def process(entity:)
|
@@ -44,6 +53,8 @@ module Cuprum::Rails::Commands
|
|
44
53
|
entity.save
|
45
54
|
|
46
55
|
entity
|
56
|
+
rescue ActiveRecord::StatementInvalid => exception
|
57
|
+
failure(invalid_statement_error(exception.message))
|
47
58
|
end
|
48
59
|
end
|
49
60
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'stannum/contracts/indifferent_hash_contract'
|
4
|
+
|
5
|
+
require 'cuprum/rails/constraints'
|
6
|
+
|
7
|
+
module Cuprum::Rails::Constraints
|
8
|
+
# Contract for validating request parameters.
|
9
|
+
class ParametersContract < Stannum::Contracts::IndifferentHashContract
|
10
|
+
def initialize(**options)
|
11
|
+
super(allow_extra_keys: true, **options)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cuprum/rails'
|
4
|
+
|
5
|
+
module Cuprum::Rails
|
6
|
+
# Namespace for Stannum constraints and contracts, which validate objects.
|
7
|
+
module Constraints
|
8
|
+
autoload :ParametersContract, 'cuprum/rails/constraints/parameters_contract'
|
9
|
+
end
|
10
|
+
end
|
@@ -1,8 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'cuprum/rails'
|
4
|
-
require 'cuprum/rails/
|
4
|
+
require 'cuprum/rails/controllers/class_methods/actions'
|
5
5
|
require 'cuprum/rails/controllers/class_methods/configuration'
|
6
|
+
require 'cuprum/rails/controllers/class_methods/middleware'
|
6
7
|
require 'cuprum/rails/controllers/class_methods/validations'
|
7
8
|
|
8
9
|
module Cuprum::Rails
|
@@ -21,7 +22,7 @@ module Cuprum::Rails
|
|
21
22
|
# class BooksController
|
22
23
|
# include Cuprum::Rails::Controller
|
23
24
|
#
|
24
|
-
# responder :html, Cuprum::Rails::Responders::Html::
|
25
|
+
# responder :html, Cuprum::Rails::Responders::Html::Resource
|
25
26
|
#
|
26
27
|
# action :index, Cuprum::Rails::Actions::Index
|
27
28
|
# action :show, Cuprum::Rails::Actions::Show, member: true
|
@@ -43,8 +44,17 @@ module Cuprum::Rails
|
|
43
44
|
|
44
45
|
other.extend(Cuprum::Rails::Controllers::ClassMethods::Actions)
|
45
46
|
other.extend(Cuprum::Rails::Controllers::ClassMethods::Configuration)
|
47
|
+
other.extend(Cuprum::Rails::Controllers::ClassMethods::Middleware)
|
46
48
|
other.extend(Cuprum::Rails::Controllers::ClassMethods::Validations)
|
47
49
|
end
|
48
50
|
end
|
51
|
+
|
52
|
+
# @api private
|
53
|
+
def action_options
|
54
|
+
{
|
55
|
+
repository: self.class.repository,
|
56
|
+
resource: self.class.resource
|
57
|
+
}
|
58
|
+
end
|
49
59
|
end
|
50
60
|
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
require 'cuprum/middleware'
|
6
|
+
|
7
|
+
require 'cuprum/rails/controllers'
|
8
|
+
|
9
|
+
module Cuprum::Rails::Controllers
|
10
|
+
# @api private
|
11
|
+
#
|
12
|
+
# Implements a controller action.
|
13
|
+
#
|
14
|
+
# @note This class should not be initialized directly. Instead, use the
|
15
|
+
# Cuprum::Rails::Controller.action class method to define an action.
|
16
|
+
class Action
|
17
|
+
extend Forwardable
|
18
|
+
|
19
|
+
# @param action_class [Class] the class of the action command. Must be
|
20
|
+
# constructible with keyword :resource.
|
21
|
+
# @param action_name [String, Symbol] the name of the action.
|
22
|
+
# @param member_action [Boolean] true if the action acts on a collection
|
23
|
+
# item, not on the collection as a whole.
|
24
|
+
def initialize(
|
25
|
+
action_class:,
|
26
|
+
action_name:,
|
27
|
+
member_action: false
|
28
|
+
)
|
29
|
+
@action_class = action_class
|
30
|
+
@action_name = action_name
|
31
|
+
@member_action = !!member_action
|
32
|
+
end
|
33
|
+
|
34
|
+
# @return [Class] the class of the action command.
|
35
|
+
attr_reader :action_class
|
36
|
+
|
37
|
+
# @return [String, Symbol] the name of the action.
|
38
|
+
attr_reader :action_name
|
39
|
+
|
40
|
+
# Executes the controller action.
|
41
|
+
#
|
42
|
+
# 1. Initializes the action command with the resource.
|
43
|
+
# 2. Calls the command with the request.
|
44
|
+
# 3. Builds the responder with the resource and action metadata.
|
45
|
+
# 4. Calls the responder with the action result.
|
46
|
+
#
|
47
|
+
# @param controller [Cuprum::Rails::Controller] the controller instance
|
48
|
+
# calling the request.
|
49
|
+
# @param request [Cuprum::Rails::Request] the request to process.
|
50
|
+
#
|
51
|
+
# @return [#call] the response object.
|
52
|
+
def call(controller, request)
|
53
|
+
responder = build_responder(controller, request)
|
54
|
+
action = apply_middleware(controller, action_class.new)
|
55
|
+
result = action.call(request: request, **controller.action_options)
|
56
|
+
|
57
|
+
responder.call(result)
|
58
|
+
end
|
59
|
+
|
60
|
+
# @return [Boolean] true if the action acts on a collection item, not on the
|
61
|
+
# collection as a whole.
|
62
|
+
def member_action?
|
63
|
+
@member_action
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def apply_middleware(controller, command)
|
69
|
+
configuration = controller.class.configuration
|
70
|
+
middleware =
|
71
|
+
configuration
|
72
|
+
.middleware_for(action_name)
|
73
|
+
.map { |config| build_middleware(config.command) }
|
74
|
+
|
75
|
+
Cuprum::Middleware.apply(
|
76
|
+
command: command,
|
77
|
+
middleware: middleware
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
def build_middleware(command)
|
82
|
+
return command unless command.is_a?(Class)
|
83
|
+
|
84
|
+
command.new
|
85
|
+
end
|
86
|
+
|
87
|
+
def build_responder(controller, request)
|
88
|
+
configuration = controller.class.configuration
|
89
|
+
responder_class = configuration.responder_for(request.format)
|
90
|
+
|
91
|
+
responder_class.new(
|
92
|
+
action_name: action_name,
|
93
|
+
controller: controller,
|
94
|
+
member_action: member_action?,
|
95
|
+
request: request,
|
96
|
+
serializers: configuration.serializers_for(request.format)
|
97
|
+
)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|