better_service 2.0.0 → 2.1.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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +2 -0
  3. data/README.md +98 -45
  4. data/Rakefile +7 -209
  5. data/config/locales/better_service.en.yml +15 -0
  6. data/lib/better_service/cache_service.rb +4 -4
  7. data/lib/better_service/concerns/instrumentation.rb +59 -14
  8. data/lib/better_service/concerns/serviceable/authorizable.rb +1 -1
  9. data/lib/better_service/concerns/serviceable/messageable.rb +70 -1
  10. data/lib/better_service/concerns/serviceable/repository_aware.rb +8 -3
  11. data/lib/better_service/concerns/workflowable/callbacks.rb +27 -27
  12. data/lib/better_service/concerns/workflowable/step.rb +39 -5
  13. data/lib/better_service/errors/better_service_error.rb +4 -0
  14. data/lib/better_service/errors/runtime/authorization_error.rb +4 -1
  15. data/lib/better_service/errors/runtime/database_error.rb +4 -1
  16. data/lib/better_service/errors/runtime/execution_error.rb +4 -1
  17. data/lib/better_service/errors/runtime/invalid_result_error.rb +28 -0
  18. data/lib/better_service/errors/runtime/resource_not_found_error.rb +4 -1
  19. data/lib/better_service/errors/runtime/validation_error.rb +4 -1
  20. data/lib/better_service/repository/base_repository.rb +1 -1
  21. data/lib/better_service/result.rb +110 -0
  22. data/lib/better_service/services/base.rb +216 -57
  23. data/lib/better_service/version.rb +1 -1
  24. data/lib/better_service/workflows/branch_group.rb +1 -1
  25. data/lib/better_service.rb +1 -6
  26. data/lib/generators/serviceable/action_generator.rb +11 -0
  27. data/lib/generators/serviceable/base_generator.rb +109 -0
  28. data/lib/generators/serviceable/create_generator.rb +11 -0
  29. data/lib/generators/serviceable/destroy_generator.rb +11 -0
  30. data/lib/generators/serviceable/index_generator.rb +11 -0
  31. data/lib/generators/serviceable/scaffold_generator.rb +29 -7
  32. data/lib/generators/serviceable/show_generator.rb +11 -0
  33. data/lib/generators/serviceable/templates/action_service.rb.tt +8 -3
  34. data/lib/generators/serviceable/templates/base_locale.en.yml.tt +53 -0
  35. data/lib/generators/serviceable/templates/base_service.rb.tt +78 -0
  36. data/lib/generators/serviceable/templates/base_service_test.rb.tt +64 -0
  37. data/lib/generators/serviceable/templates/create_service.rb.tt +29 -18
  38. data/lib/generators/serviceable/templates/destroy_service.rb.tt +16 -29
  39. data/lib/generators/serviceable/templates/index_service.rb.tt +16 -34
  40. data/lib/generators/serviceable/templates/repository.rb.tt +76 -0
  41. data/lib/generators/serviceable/templates/repository_test.rb.tt +124 -0
  42. data/lib/generators/serviceable/templates/show_service.rb.tt +10 -38
  43. data/lib/generators/serviceable/templates/update_service.rb.tt +24 -38
  44. data/lib/generators/serviceable/update_generator.rb +11 -0
  45. metadata +13 -12
  46. data/lib/better_service/concerns/serviceable/viewable.rb +0 -33
  47. data/lib/better_service/services/action_service.rb +0 -60
  48. data/lib/better_service/services/create_service.rb +0 -63
  49. data/lib/better_service/services/destroy_service.rb +0 -60
  50. data/lib/better_service/services/index_service.rb +0 -56
  51. data/lib/better_service/services/show_service.rb +0 -44
  52. data/lib/better_service/services/update_service.rb +0 -61
@@ -1,14 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  <% module_namespacing do -%>
4
- class <%= class_name %>::ShowService < BetterService::Services::ShowService
5
- # Optional: Use a presenter to format response data
6
- # Generate with: rails generate better_service:presenter <%= class_name %>
7
- #
8
- # presenter <%= class_name %>Presenter
9
- # presenter_options do
10
- # { current_user: user }
11
- # end
4
+ class <%= class_name %>::ShowService < <%= parent_class %>
5
+ # Action name for metadata
6
+ performed_action :showed
12
7
 
13
8
  # Schema for validating params
14
9
  schema do
@@ -17,39 +12,16 @@ class <%= class_name %>::ShowService < BetterService::Services::ShowService
17
12
 
18
13
  # Phase 1: Search - Load the resource
19
14
  search_with do
20
- { resource: user.<%= plural_table_name %>.find(params[:id]) }
15
+ <% if using_base_service? -%>
16
+ { object: <%= singular_table_name %>_repository.find(params[:id]) }
17
+ <% else -%>
18
+ { object: user.<%= plural_table_name %>.find(params[:id]) }
19
+ <% end -%>
21
20
  end
22
21
 
23
- # Phase 2: Process - Transform data (optional)
24
- # process_with do |data|
25
- # data
26
- # end
27
-
28
- # Phase 4: Respond - Format response (optional override)
29
- # Uses I18n message helper with fallback to default messages
30
- #
31
- # To customize messages, create config/locales/<%= plural_table_name %>_services.en.yml:
32
- # en:
33
- # <%= plural_table_name %>:
34
- # services:
35
- # show:
36
- # success: "<%= human_name %> loaded successfully!"
37
- #
38
- # Then configure namespace: messages_namespace :<%= plural_table_name %>
22
+ # Phase 4: Respond - Format response
39
23
  respond_with do |data|
40
- success_result(message("show.success"), data)
24
+ success_for(data[:object], message("show.success"))
41
25
  end
42
-
43
- # Phase 5: Viewer - UI configuration (optional)
44
- # viewer do |processed, transformed, result|
45
- # {
46
- # page_title: "<%= human_name %> ##{result[:resource].id}",
47
- # breadcrumbs: [
48
- # { label: "Home", url: "/" },
49
- # { label: "<%= plural_table_name.titleize %>", url: "/<%= plural_table_name %>" },
50
- # { label: "Show", url: "#" }
51
- # ]
52
- # }
53
- # end
54
26
  end
55
27
  <% end -%>
@@ -1,10 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  <% module_namespacing do -%>
4
- class <%= class_name %>::UpdateService < BetterService::Services::UpdateService
5
- # Database transactions are ENABLED by default for update operations
6
- # The process block will automatically run inside a transaction
7
- # To disable: with_transaction false
4
+ class <%= class_name %>::UpdateService < <%= parent_class %>
5
+ # Action name for metadata
6
+ performed_action :updated
7
+
8
+ # Enable transaction wrapping
9
+ with_transaction true
8
10
 
9
11
  # Schema for validating params
10
12
  schema do
@@ -12,49 +14,33 @@ class <%= class_name %>::UpdateService < BetterService::Services::UpdateService
12
14
  # Add your optional attributes here
13
15
  end
14
16
 
15
- # Authorization (optional) - Runs BEFORE search phase
16
- # Uncomment and customize for your needs:
17
- #
18
- # authorize_with do
19
- # # Example 1: Simple role check
20
- # user.admin?
21
- #
22
- # # Example 2: Resource ownership check
23
- # <%= file_name %> = <%= class_name %>.find(params[:id])
24
- # <%= file_name %>.user_id == user.id
25
- #
26
- # # Example 3: Pundit integration
27
- # <%= class_name %>Policy.new(user, <%= class_name %>.find(params[:id])).update?
28
- #
29
- # # Example 4: CanCanCan integration
30
- # Ability.new(user).can?(:update, :<%= file_name %>)
31
- # end
32
-
33
17
  # Phase 1: Search - Load the resource
34
18
  search_with do
35
- { resource: user.<%= plural_table_name %>.find(params[:id]) }
19
+ <% if using_base_service? -%>
20
+ { object: <%= singular_table_name %>_repository.find(params[:id]) }
21
+ <% else -%>
22
+ { object: user.<%= plural_table_name %>.find(params[:id]) }
23
+ <% end -%>
36
24
  end
37
25
 
38
26
  # Phase 2: Process - Update the resource (runs in transaction)
27
+ # Uses update (not update!) to allow graceful validation handling
39
28
  process_with do |data|
40
- <%= file_name %> = data[:resource]
41
- <%= file_name %>.update!(params.except(:id))
42
- { resource: <%= file_name %> }
29
+ record = data[:object]
30
+
31
+ if record.update(params.except(:id))
32
+ { object: record }
33
+ else
34
+ failure_for(record)
35
+ end
43
36
  end
44
37
 
45
- # Phase 4: Respond - Format response (optional override)
46
- # Uses I18n message helper with fallback to default messages
47
- #
48
- # To customize messages, create config/locales/<%= plural_table_name %>_services.en.yml:
49
- # en:
50
- # <%= plural_table_name %>:
51
- # services:
52
- # update:
53
- # success: "<%= human_name %> updated successfully!"
54
- #
55
- # Then configure namespace: messages_namespace :<%= plural_table_name %>
38
+ # Phase 4: Respond - Format response
56
39
  respond_with do |data|
57
- success_result(message("update.success"), data)
40
+ # Pass through failure responses
41
+ return data if data[:success] == false
42
+
43
+ success_for(data[:object], message("update.success"))
58
44
  end
59
45
  end
60
46
  <% end -%>
@@ -9,6 +9,9 @@ module Serviceable
9
9
 
10
10
  desc "Generate an Update service for modifying resources"
11
11
 
12
+ class_option :base_class, type: :string, default: nil,
13
+ desc: "Custom base class to inherit from (e.g., Articles::BaseService)"
14
+
12
15
  def create_service_file
13
16
  template "update_service.rb.tt", File.join("app/services", class_path, "#{file_name}/update_service.rb")
14
17
  end
@@ -22,6 +25,14 @@ module Serviceable
22
25
  def service_class_name
23
26
  "#{class_name}::UpdateService"
24
27
  end
28
+
29
+ def parent_class
30
+ options[:base_class] || "BetterService::Services::Base"
31
+ end
32
+
33
+ def using_base_service?
34
+ options[:base_class].present?
35
+ end
25
36
  end
26
37
  end
27
38
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: better_service
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - alessiobussolari
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-11-28 00:00:00.000000000 Z
11
+ date: 2025-12-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -75,7 +75,7 @@ dependencies:
75
75
  description: A powerful DSL-based framework for building Service Objects in Rails
76
76
  with built-in support for validation, caching, presenters, and more.
77
77
  email:
78
- - alessio@cosmic.tech
78
+ - alessio.bussolari@pandev.it
79
79
  executables: []
80
80
  extensions: []
81
81
  extra_rdoc_files: []
@@ -95,7 +95,6 @@ files:
95
95
  - lib/better_service/concerns/serviceable/repository_aware.rb
96
96
  - lib/better_service/concerns/serviceable/transactional.rb
97
97
  - lib/better_service/concerns/serviceable/validatable.rb
98
- - lib/better_service/concerns/serviceable/viewable.rb
99
98
  - lib/better_service/concerns/workflowable.rb
100
99
  - lib/better_service/concerns/workflowable/callbacks.rb
101
100
  - lib/better_service/concerns/workflowable/context.rb
@@ -110,6 +109,7 @@ files:
110
109
  - lib/better_service/errors/runtime/authorization_error.rb
111
110
  - lib/better_service/errors/runtime/database_error.rb
112
111
  - lib/better_service/errors/runtime/execution_error.rb
112
+ - lib/better_service/errors/runtime/invalid_result_error.rb
113
113
  - lib/better_service/errors/runtime/resource_not_found_error.rb
114
114
  - lib/better_service/errors/runtime/runtime_error.rb
115
115
  - lib/better_service/errors/runtime/transaction_error.rb
@@ -125,13 +125,8 @@ files:
125
125
  - lib/better_service/presenter.rb
126
126
  - lib/better_service/railtie.rb
127
127
  - lib/better_service/repository/base_repository.rb
128
- - lib/better_service/services/action_service.rb
128
+ - lib/better_service/result.rb
129
129
  - lib/better_service/services/base.rb
130
- - lib/better_service/services/create_service.rb
131
- - lib/better_service/services/destroy_service.rb
132
- - lib/better_service/services/index_service.rb
133
- - lib/better_service/services/show_service.rb
134
- - lib/better_service/services/update_service.rb
135
130
  - lib/better_service/subscribers/log_subscriber.rb
136
131
  - lib/better_service/subscribers/stats_subscriber.rb
137
132
  - lib/better_service/version.rb
@@ -152,15 +147,21 @@ files:
152
147
  - lib/generators/better_service/templates/presenter.rb.tt
153
148
  - lib/generators/better_service/templates/presenter_test.rb.tt
154
149
  - lib/generators/serviceable/action_generator.rb
150
+ - lib/generators/serviceable/base_generator.rb
155
151
  - lib/generators/serviceable/create_generator.rb
156
152
  - lib/generators/serviceable/destroy_generator.rb
157
153
  - lib/generators/serviceable/index_generator.rb
158
154
  - lib/generators/serviceable/scaffold_generator.rb
159
155
  - lib/generators/serviceable/show_generator.rb
160
156
  - lib/generators/serviceable/templates/action_service.rb.tt
157
+ - lib/generators/serviceable/templates/base_locale.en.yml.tt
158
+ - lib/generators/serviceable/templates/base_service.rb.tt
159
+ - lib/generators/serviceable/templates/base_service_test.rb.tt
161
160
  - lib/generators/serviceable/templates/create_service.rb.tt
162
161
  - lib/generators/serviceable/templates/destroy_service.rb.tt
163
162
  - lib/generators/serviceable/templates/index_service.rb.tt
163
+ - lib/generators/serviceable/templates/repository.rb.tt
164
+ - lib/generators/serviceable/templates/repository_test.rb.tt
164
165
  - lib/generators/serviceable/templates/service_test.rb.tt
165
166
  - lib/generators/serviceable/templates/show_service.rb.tt
166
167
  - lib/generators/serviceable/templates/update_service.rb.tt
@@ -185,14 +186,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
185
186
  requirements:
186
187
  - - ">="
187
188
  - !ruby/object:Gem::Version
188
- version: 3.0.0
189
+ version: 3.2.0
189
190
  required_rubygems_version: !ruby/object:Gem::Requirement
190
191
  requirements:
191
192
  - - ">="
192
193
  - !ruby/object:Gem::Version
193
194
  version: '0'
194
195
  requirements: []
195
- rubygems_version: 3.5.22
196
+ rubygems_version: 3.5.11
196
197
  signing_key:
197
198
  specification_version: 4
198
199
  summary: DSL-based Service Objects framework for Rails
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module BetterService
4
- module Concerns
5
- module Serviceable
6
- module Viewable
7
- extend ActiveSupport::Concern
8
-
9
- included do
10
- class_attribute :_viewer_enabled, default: false
11
- class_attribute :_viewer_block, default: nil
12
- end
13
-
14
- class_methods do
15
- def viewer(enabled = true, &block)
16
- self._viewer_enabled = enabled
17
- self._viewer_block = block if block_given?
18
- end
19
- end
20
-
21
- private
22
-
23
- def viewer_enabled?
24
- self.class._viewer_enabled && self.class._viewer_block.present?
25
- end
26
-
27
- def execute_viewer(processed, transformed, result)
28
- instance_exec(processed, transformed, result, &self.class._viewer_block)
29
- end
30
- end
31
- end
32
- end
33
- end
@@ -1,60 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "base"
4
-
5
- module BetterService
6
- module Services
7
- # ActionService - Specialized service for custom actions/transitions
8
- #
9
- # Returns: { resource: {}, metadata: { action: :custom_action_name } }
10
- #
11
- # Example:
12
- # class Orders::ConfirmService < BetterService::Services::ActionService
13
- # action_name :confirmed # Sets metadata action
14
- #
15
- # schema do
16
- # required(:id).filled(:integer)
17
- # end
18
- #
19
- # search_with do
20
- # { resource: user.orders.find(params[:id]) }
21
- # end
22
- #
23
- # process_with do |data|
24
- # order = data[:resource]
25
- # order.update!(status: 'confirmed', confirmed_at: Time.current)
26
- # { resource: order }
27
- # end
28
- # end
29
- class ActionService < Services::Base
30
- # Default action_name to nil - subclasses MUST set it
31
- self._action_name = nil
32
-
33
- def self.action_name(name)
34
- self._action_name = name.to_sym
35
- end
36
-
37
- # Default schema - requires id parameter for actions
38
- schema do
39
- required(:id).filled
40
- end
41
-
42
- private
43
-
44
- # Override respond to ensure resource key is present
45
- def respond(data)
46
- # Get base result (from custom respond_with block or default)
47
- if self.class._respond_block
48
- result = instance_exec(data, &self.class._respond_block)
49
- else
50
- result = success_result("Action completed successfully", data)
51
- end
52
-
53
- # Ensure resource key exists (default to nil if not provided)
54
- result[:resource] ||= nil
55
-
56
- result
57
- end
58
- end
59
- end
60
- end
@@ -1,63 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "base"
4
-
5
- module BetterService
6
- module Services
7
- # CreateService - Specialized service for creating new resources
8
- #
9
- # Returns: { resource: {}, metadata: { action: :created } }
10
- #
11
- # Example:
12
- # class Orders::CreateService < BetterService::Services::CreateService
13
- # schema do
14
- # required(:title).filled(:string)
15
- # required(:total).filled(:decimal)
16
- # end
17
- #
18
- # search_with do
19
- # {}
20
- # end
21
- #
22
- # process_with do |data|
23
- # order = user.orders.create!(
24
- # title: params[:title],
25
- # total: params[:total]
26
- # )
27
- # { resource: order }
28
- # end
29
- # end
30
- class CreateService < Services::Base
31
- # Set action_name for metadata
32
- self._action_name = :created
33
-
34
- # Enable database transactions by default for create operations
35
- with_transaction true
36
-
37
- # Enable automatic cache invalidation for create operations
38
- self._auto_invalidate_cache = true
39
-
40
- # Default empty schema - subclasses MUST override with specific validations
41
- schema do
42
- # Override in subclass with required fields
43
- end
44
-
45
- private
46
-
47
- # Override respond to ensure resource key is present
48
- def respond(data)
49
- # Get base result (from custom respond_with block or default)
50
- if self.class._respond_block
51
- result = instance_exec(data, &self.class._respond_block)
52
- else
53
- result = success_result("Resource created successfully", data)
54
- end
55
-
56
- # Ensure resource key exists (default to nil if not provided)
57
- result[:resource] ||= nil
58
-
59
- result
60
- end
61
- end
62
- end
63
- end
@@ -1,60 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "base"
4
-
5
- module BetterService
6
- module Services
7
- # DestroyService - Specialized service for deleting resources
8
- #
9
- # Returns: { resource: {}, metadata: { action: :deleted } }
10
- #
11
- # Example:
12
- # class Orders::DestroyService < BetterService::Services::DestroyService
13
- # schema do
14
- # required(:id).filled(:integer)
15
- # end
16
- #
17
- # search_with do
18
- # { resource: user.orders.find(params[:id]) }
19
- # end
20
- #
21
- # process_with do |data|
22
- # order = data[:resource]
23
- # order.destroy!
24
- # { resource: order }
25
- # end
26
- # end
27
- class DestroyService < Services::Base
28
- # Set action_name for metadata
29
- self._action_name = :deleted
30
-
31
- # Enable database transactions by default for destroy operations
32
- with_transaction true
33
-
34
- # Enable automatic cache invalidation for destroy operations
35
- self._auto_invalidate_cache = true
36
-
37
- # Default schema - requires id parameter
38
- schema do
39
- required(:id).filled
40
- end
41
-
42
- private
43
-
44
- # Override respond to ensure resource key is present
45
- def respond(data)
46
- # Get base result (from custom respond_with block or default)
47
- if self.class._respond_block
48
- result = instance_exec(data, &self.class._respond_block)
49
- else
50
- result = success_result("Resource deleted successfully", data)
51
- end
52
-
53
- # Ensure resource key exists (default to nil if not provided)
54
- result[:resource] ||= nil
55
-
56
- result
57
- end
58
- end
59
- end
60
- end
@@ -1,56 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "base"
4
-
5
- module BetterService
6
- module Services
7
- # IndexService - Specialized service for list/collection endpoints
8
- #
9
- # Returns: { items: [], metadata: { action: :index, stats: {}, pagination: {} } }
10
- #
11
- # Example:
12
- # class Orders::IndexService < BetterService::Services::IndexService
13
- # search_with do
14
- # { items: user.orders.to_a }
15
- # end
16
- #
17
- # process_with do |data|
18
- # {
19
- # items: data[:items],
20
- # metadata: {
21
- # stats: { total: data[:items].count },
22
- # pagination: { page: params[:page] || 1 }
23
- # }
24
- # }
25
- # end
26
- # end
27
- class IndexService < Services::Base
28
- # Set action_name for metadata
29
- self._action_name = :index
30
-
31
- # Default schema - can be overridden in subclasses
32
- schema do
33
- optional(:page).filled(:integer, gteq?: 1)
34
- optional(:per_page).filled(:integer, gteq?: 1, lteq?: 100)
35
- optional(:search).maybe(:string)
36
- end
37
-
38
- private
39
-
40
- # Override respond to ensure items key is present
41
- def respond(data)
42
- # Get base result (from custom respond_with block or default)
43
- if self.class._respond_block
44
- result = instance_exec(data, &self.class._respond_block)
45
- else
46
- result = success_result("Operation completed successfully", data)
47
- end
48
-
49
- # Ensure items key exists (default to empty array if not provided)
50
- result[:items] ||= []
51
-
52
- result
53
- end
54
- end
55
- end
56
- end
@@ -1,44 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "base"
4
-
5
- module BetterService
6
- module Services
7
- # ShowService - Specialized service for single resource detail endpoints
8
- #
9
- # Returns: { resource: {}, metadata: { action: :show } }
10
- #
11
- # Example:
12
- # class Orders::ShowService < BetterService::Services::ShowService
13
- # search_with do
14
- # { resource: user.orders.find(params[:id]) }
15
- # end
16
- # end
17
- class ShowService < Services::Base
18
- # Set action_name for metadata
19
- self._action_name = :show
20
-
21
- # Default schema - requires id parameter
22
- schema do
23
- required(:id).filled
24
- end
25
-
26
- private
27
-
28
- # Override respond to ensure resource key is present
29
- def respond(data)
30
- # Get base result (from custom respond_with block or default)
31
- if self.class._respond_block
32
- result = instance_exec(data, &self.class._respond_block)
33
- else
34
- result = success_result("Operation completed successfully", data)
35
- end
36
-
37
- # Ensure resource key exists (default to nil if not provided)
38
- result[:resource] ||= nil
39
-
40
- result
41
- end
42
- end
43
- end
44
- end
@@ -1,61 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "base"
4
-
5
- module BetterService
6
- module Services
7
- # UpdateService - Specialized service for updating existing resources
8
- #
9
- # Returns: { resource: {}, metadata: { action: :updated } }
10
- #
11
- # Example:
12
- # class Orders::UpdateService < BetterService::Services::UpdateService
13
- # schema do
14
- # required(:id).filled(:integer)
15
- # optional(:title).filled(:string)
16
- # end
17
- #
18
- # search_with do
19
- # { resource: user.orders.find(params[:id]) }
20
- # end
21
- #
22
- # process_with do |data|
23
- # order = data[:resource]
24
- # order.update!(params.except(:id))
25
- # { resource: order }
26
- # end
27
- # end
28
- class UpdateService < Services::Base
29
- # Set action_name for metadata
30
- self._action_name = :updated
31
-
32
- # Enable database transactions by default for update operations
33
- with_transaction true
34
-
35
- # Enable automatic cache invalidation for update operations
36
- self._auto_invalidate_cache = true
37
-
38
- # Default schema - requires id parameter
39
- schema do
40
- required(:id).filled
41
- end
42
-
43
- private
44
-
45
- # Override respond to ensure resource key is present
46
- def respond(data)
47
- # Get base result (from custom respond_with block or default)
48
- if self.class._respond_block
49
- result = instance_exec(data, &self.class._respond_block)
50
- else
51
- result = success_result("Resource updated successfully", data)
52
- end
53
-
54
- # Ensure resource key exists (default to nil if not provided)
55
- result[:resource] ||= nil
56
-
57
- result
58
- end
59
- end
60
- end
61
- end