better_controller 0.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 (40) hide show
  1. checksums.yaml +7 -0
  2. data/.DS_Store +0 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +95 -0
  5. data/CHANGELOG.md +18 -0
  6. data/CODE_OF_CONDUCT.md +132 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +624 -0
  9. data/Rakefile +12 -0
  10. data/examples/api_controller.rb +31 -0
  11. data/examples/application_controller.rb +51 -0
  12. data/examples/products_controller.rb +25 -0
  13. data/examples/user_serializer.rb +15 -0
  14. data/examples/user_service.rb +31 -0
  15. data/examples/users_controller.rb +86 -0
  16. data/lib/better_controller/action_helpers.rb +76 -0
  17. data/lib/better_controller/base.rb +61 -0
  18. data/lib/better_controller/configuration.rb +69 -0
  19. data/lib/better_controller/logging.rb +101 -0
  20. data/lib/better_controller/method_not_overridden_error.rb +13 -0
  21. data/lib/better_controller/pagination.rb +44 -0
  22. data/lib/better_controller/parameter_validation.rb +86 -0
  23. data/lib/better_controller/params_helpers.rb +109 -0
  24. data/lib/better_controller/railtie.rb +18 -0
  25. data/lib/better_controller/resources_controller.rb +263 -0
  26. data/lib/better_controller/response_helpers.rb +74 -0
  27. data/lib/better_controller/serializer.rb +85 -0
  28. data/lib/better_controller/service.rb +94 -0
  29. data/lib/better_controller/version.rb +5 -0
  30. data/lib/better_controller.rb +55 -0
  31. data/lib/generators/better_controller/controller_generator.rb +65 -0
  32. data/lib/generators/better_controller/install_generator.rb +22 -0
  33. data/lib/generators/better_controller/templates/README +87 -0
  34. data/lib/generators/better_controller/templates/controller.rb +78 -0
  35. data/lib/generators/better_controller/templates/initializer.rb +31 -0
  36. data/lib/generators/better_controller/templates/serializer.rb +32 -0
  37. data/lib/generators/better_controller/templates/service.rb +57 -0
  38. data/lib/tasks/better_controller_tasks.rake +61 -0
  39. data/sig/better_controller.rbs +4 -0
  40. metadata +226 -0
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BetterController
4
+ module Generators
5
+ # Generator for creating a controller with BetterController
6
+ class ControllerGenerator < Rails::Generators::NamedBase
7
+ source_root File.expand_path('templates', __dir__)
8
+
9
+ argument :actions, type: :array, default: [], banner: 'action action'
10
+ class_option :skip_service, type: :boolean, default: false, desc: 'Skip generating a service'
11
+ class_option :skip_serializer, type: :boolean, default: false, desc: 'Skip generating a serializer'
12
+ class_option :model, type: :string, desc: 'Specify the model name (defaults to singular of controller name)'
13
+
14
+ def create_controller_file
15
+ template 'controller.rb', File.join('app/controllers', "#{file_name}_controller.rb")
16
+ end
17
+
18
+ def create_service_file
19
+ return if options[:skip_service]
20
+
21
+ template 'service.rb', File.join('app/services', "#{service_file_name}_service.rb")
22
+ end
23
+
24
+ def create_serializer_file
25
+ return if options[:skip_serializer]
26
+
27
+ template 'serializer.rb', File.join('app/serializers', "#{serializer_file_name}_serializer.rb")
28
+ end
29
+
30
+ private
31
+
32
+ def model_name
33
+ options[:model] || file_name.singularize
34
+ end
35
+
36
+ def service_file_name
37
+ model_name.underscore
38
+ end
39
+
40
+ def serializer_file_name
41
+ model_name.underscore
42
+ end
43
+
44
+ def model_class_name
45
+ model_name.camelize
46
+ end
47
+
48
+ def service_class_name
49
+ "#{model_class_name}Service"
50
+ end
51
+
52
+ def serializer_class_name
53
+ "#{model_class_name}Serializer"
54
+ end
55
+
56
+ def controller_actions
57
+ actions.map(&:to_sym)
58
+ end
59
+
60
+ def has_action?(action)
61
+ controller_actions.include?(action.to_sym) || controller_actions.empty?
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BetterController
4
+ module Generators
5
+ # Generator for installing BetterController
6
+ class InstallGenerator < Rails::Generators::Base
7
+ source_root File.expand_path('templates', __dir__)
8
+
9
+ def create_initializer
10
+ template 'initializer.rb', 'config/initializers/better_controller.rb'
11
+ end
12
+
13
+ def mount_routes
14
+ route '# BetterController routes can be added here'
15
+ end
16
+
17
+ def show_readme
18
+ readme 'README' if behavior == :invoke
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,87 @@
1
+ # BetterController
2
+
3
+ BetterController has been successfully installed!
4
+
5
+ ## Getting Started
6
+
7
+ ### Configuration
8
+
9
+ An initializer has been created at `config/initializers/better_controller.rb`.
10
+ You can modify the configuration options to suit your needs.
11
+
12
+ ### Generating Controllers
13
+
14
+ You can generate a controller with BetterController using the following command:
15
+
16
+ ```bash
17
+ rails generate better_controller:controller Users index show create update destroy
18
+ ```
19
+
20
+ This will create:
21
+ - A UsersController with the specified actions
22
+ - A UserService for handling business logic
23
+ - A UserSerializer for serializing responses
24
+
25
+ ### Customizing Controllers
26
+
27
+ You can customize the generated controllers by overriding the following methods:
28
+
29
+ ```ruby
30
+ # Define the resource service class
31
+ def resource_service_class
32
+ UserService
33
+ end
34
+
35
+ # Define the root key for resource parameters
36
+ def resource_params_root_key
37
+ :user
38
+ end
39
+
40
+ # Define the resource serializer class
41
+ def resource_serializer
42
+ UserSerializer
43
+ end
44
+ ```
45
+
46
+ ### Using Services
47
+
48
+ Services handle the business logic for your resources. You can customize them by overriding methods:
49
+
50
+ ```ruby
51
+ # Define permitted attributes
52
+ def permitted_attributes
53
+ [:name, :email, :password]
54
+ end
55
+
56
+ # Add custom validation
57
+ def validate_create(attributes)
58
+ raise BetterController::Error.new("Email is required") if attributes[:email].blank?
59
+ end
60
+ ```
61
+
62
+ ### Using Serializers
63
+
64
+ Serializers define how your resources are presented in responses:
65
+
66
+ ```ruby
67
+ # Define attributes to include
68
+ attributes :id, :name, :email, :created_at
69
+
70
+ # Define methods for calculated fields
71
+ methods :full_name
72
+
73
+ # Define associations to include
74
+ has_many :posts
75
+ belongs_to :company
76
+
77
+ # Define a method that returns a calculated field
78
+ def full_name
79
+ "#{object.first_name} #{object.last_name}"
80
+ end
81
+ ```
82
+
83
+ ## Documentation
84
+
85
+ For more information, please refer to the BetterController documentation.
86
+
87
+ Happy coding!
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ class <%= class_name %>Controller < ApplicationController
4
+ include BetterController::ResourcesController
5
+
6
+ <% if has_action?(:index) -%>
7
+ # GET /<%= file_name %>
8
+ def index
9
+ execute_action do
10
+ @resource_collection = resource_collection_resolver
11
+ data = serialize_resource(@resource_collection, index_serializer)
12
+ respond_with_success(data, options: { meta: meta })
13
+ end
14
+ end
15
+ <% end -%>
16
+
17
+ <% if has_action?(:show) -%>
18
+ # GET /<%= file_name %>/:id
19
+ def show
20
+ execute_action do
21
+ @resource = resource_resolver
22
+ data = serialize_resource(@resource, show_serializer)
23
+ respond_with_success(data)
24
+ end
25
+ end
26
+ <% end -%>
27
+
28
+ <% if has_action?(:create) -%>
29
+ # POST /<%= file_name %>
30
+ def create
31
+ execute_action do
32
+ @resource = resource_service.create(resource_params)
33
+ data = serialize_resource(@resource, create_serializer)
34
+ respond_with_success(data, status: :created)
35
+ end
36
+ end
37
+ <% end -%>
38
+
39
+ <% if has_action?(:update) -%>
40
+ # PATCH/PUT /<%= file_name %>/:id
41
+ def update
42
+ execute_action do
43
+ @resource = resource_resolver
44
+ resource_service.update(@resource, resource_params)
45
+ data = serialize_resource(@resource, update_serializer)
46
+ respond_with_success(data)
47
+ end
48
+ end
49
+ <% end -%>
50
+
51
+ <% if has_action?(:destroy) -%>
52
+ # DELETE /<%= file_name %>/:id
53
+ def destroy
54
+ execute_action do
55
+ @resource = resource_resolver
56
+ resource_service.destroy(@resource)
57
+ respond_with_success(nil, status: :no_content)
58
+ end
59
+ end
60
+ <% end -%>
61
+
62
+ protected
63
+
64
+ # Define the resource service class
65
+ def resource_service_class
66
+ <%= service_class_name %>
67
+ end
68
+
69
+ # Define the root key for resource parameters
70
+ def resource_params_root_key
71
+ :<%= model_name.underscore %>
72
+ end
73
+
74
+ # Define the resource serializer class
75
+ def resource_serializer
76
+ <%= serializer_class_name %>
77
+ end
78
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ # BetterController Configuration
4
+ BetterController.configure do |config|
5
+ # Pagination configuration
6
+ config[:pagination] = {
7
+ # Enable pagination for ResourcesController
8
+ enabled: true,
9
+ # Default number of items per page
10
+ per_page: 25,
11
+ }
12
+
13
+ # Serialization configuration
14
+ config[:serialization] = {
15
+ # Include root key in JSON response
16
+ include_root: false,
17
+ # Camelize keys in JSON response
18
+ camelize_keys: true,
19
+ }
20
+
21
+ # Error handling configuration
22
+ config[:error_handling] = {
23
+ # Log errors to Rails logger
24
+ log_errors: true,
25
+ # Include detailed error information in responses
26
+ detailed_errors: true,
27
+ }
28
+ end
29
+
30
+ # Optional: Configure custom logger
31
+ # BetterController::Logging.logger = Rails.logger
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ class <%= serializer_class_name %> < BetterController::Serializer
4
+ # Define the attributes to include in the serialized output
5
+ attributes :id,
6
+ :created_at,
7
+ :updated_at
8
+ # Add your model attributes here
9
+
10
+ # Define methods to include in the serialized output
11
+ # methods :calculated_field
12
+
13
+ # Define associations to include in the serialized output
14
+ # has_many :related_items
15
+ # has_one :related_item
16
+ # belongs_to :parent_item
17
+
18
+ # Optional: Define a custom serializer for a specific association
19
+ # has_many :related_items, serializer: RelatedItemSerializer
20
+
21
+ # Optional: Define a method that returns a calculated field
22
+ # def calculated_field
23
+ # # Add your calculation logic here
24
+ # object.some_attribute * 2
25
+ # end
26
+
27
+ # Optional: Define a method that conditionally includes an attribute
28
+ # def include_some_attribute?
29
+ # # Add your condition logic here
30
+ # object.some_condition?
31
+ # end
32
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ class <%= service_class_name %> < BetterController::Service
4
+ # Define the model class for this service
5
+ def model_class
6
+ <%= model_class_name %>
7
+ end
8
+
9
+ # Define the permitted attributes for create and update operations
10
+ def permitted_attributes
11
+ [
12
+ # Add your permitted attributes here
13
+ # Examples:
14
+ # :name,
15
+ # :email,
16
+ # { address_attributes: [:street, :city, :state, :zip] }
17
+ ]
18
+ end
19
+
20
+ # Optional: Override the default query for finding resources
21
+ # def find_query(id)
22
+ # model_class.includes(:associations).find(id)
23
+ # end
24
+
25
+ # Optional: Override the default query for listing resources
26
+ # def list_query
27
+ # model_class.includes(:associations).all
28
+ # end
29
+
30
+ # Optional: Add custom validation before create
31
+ # def validate_create(attributes)
32
+ # # Add your validation logic here
33
+ # # Raise BetterController::Error.new("Custom error message") if validation fails
34
+ # end
35
+
36
+ # Optional: Add custom validation before update
37
+ # def validate_update(resource, attributes)
38
+ # # Add your validation logic here
39
+ # # Raise BetterController::Error.new("Custom error message") if validation fails
40
+ # end
41
+
42
+ # Optional: Add custom logic after create
43
+ # def after_create(resource)
44
+ # # Add your after create logic here
45
+ # end
46
+
47
+ # Optional: Add custom logic after update
48
+ # def after_update(resource)
49
+ # # Add your after update logic here
50
+ # end
51
+
52
+ # Optional: Add custom logic before destroy
53
+ # def before_destroy(resource)
54
+ # # Add your before destroy logic here
55
+ # # Return false to prevent destruction
56
+ # end
57
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :better_controller do
4
+ desc 'Print the BetterController version'
5
+ task version: :environment do
6
+ require 'better_controller/version'
7
+ puts "BetterController version: #{BetterController::VERSION}"
8
+ end
9
+
10
+ desc 'Generate a new controller using BetterController'
11
+ task :generate_controller, %i[name model] => :environment do |_, args|
12
+ name = args[:name]
13
+ model = args[:model]
14
+
15
+ if name.blank?
16
+ puts 'Error: Controller name is required'
17
+ puts 'Usage: rake better_controller:generate_controller[name,model]'
18
+ next
19
+ end
20
+
21
+ model_class = model.presence || name.singularize
22
+ controller_name = "#{name.camelize}Controller"
23
+ file_path = Rails.root.join('app', 'controllers', "#{name.underscore}_controller.rb")
24
+
25
+ template = <<~RUBY
26
+ # frozen_string_literal: true
27
+
28
+ class #{controller_name} < ApplicationController
29
+ include BetterController::ResourcesController
30
+ #{' '}
31
+ # Define required parameters for actions
32
+ requires_params :create, :id # Add your required params
33
+ #{' '}
34
+ # Define parameter schema for validation
35
+ param_schema :create, {
36
+ # Add your parameter schema here
37
+ }
38
+ #{' '}
39
+ protected
40
+ #{' '}
41
+ # Define the resource service class
42
+ def resource_service_class
43
+ #{model_class.camelize}Service
44
+ end
45
+ #{' '}
46
+ # Define the root key for resource parameters
47
+ def resource_params_root_key
48
+ :#{model_class.underscore}
49
+ end
50
+ #{' '}
51
+ # Define the resource serializer class
52
+ def resource_serializer
53
+ #{model_class.camelize}Serializer
54
+ end
55
+ end
56
+ RUBY
57
+
58
+ File.write(file_path, template)
59
+ puts "Created controller at #{file_path}"
60
+ end
61
+ end
@@ -0,0 +1,4 @@
1
+ module BetterController
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,226 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: better_controller
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - alessiobussolari
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2025-03-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: actionpack
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '6.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '6.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '6.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '6.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: kaminari
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.2'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.2'
55
+ - !ruby/object:Gem::Dependency
56
+ name: zeitwerk
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.6'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.6'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rails
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '6.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '6.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec-rails
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '5.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '5.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.50'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.50'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop-rails
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '2.19'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '2.19'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rubocop-rspec
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '2.22'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '2.22'
139
+ - !ruby/object:Gem::Dependency
140
+ name: simplecov
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '0.22'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '0.22'
153
+ description: BetterController provides tools and utilities to improve Rails controllers,
154
+ making them more maintainable and feature-rich.
155
+ email:
156
+ - alessio@cosmic.tech
157
+ executables: []
158
+ extensions: []
159
+ extra_rdoc_files: []
160
+ files:
161
+ - ".DS_Store"
162
+ - ".rspec"
163
+ - ".rubocop.yml"
164
+ - CHANGELOG.md
165
+ - CODE_OF_CONDUCT.md
166
+ - LICENSE.txt
167
+ - README.md
168
+ - Rakefile
169
+ - examples/api_controller.rb
170
+ - examples/application_controller.rb
171
+ - examples/products_controller.rb
172
+ - examples/user_serializer.rb
173
+ - examples/user_service.rb
174
+ - examples/users_controller.rb
175
+ - lib/better_controller.rb
176
+ - lib/better_controller/action_helpers.rb
177
+ - lib/better_controller/base.rb
178
+ - lib/better_controller/configuration.rb
179
+ - lib/better_controller/logging.rb
180
+ - lib/better_controller/method_not_overridden_error.rb
181
+ - lib/better_controller/pagination.rb
182
+ - lib/better_controller/parameter_validation.rb
183
+ - lib/better_controller/params_helpers.rb
184
+ - lib/better_controller/railtie.rb
185
+ - lib/better_controller/resources_controller.rb
186
+ - lib/better_controller/response_helpers.rb
187
+ - lib/better_controller/serializer.rb
188
+ - lib/better_controller/service.rb
189
+ - lib/better_controller/version.rb
190
+ - lib/generators/better_controller/controller_generator.rb
191
+ - lib/generators/better_controller/install_generator.rb
192
+ - lib/generators/better_controller/templates/README
193
+ - lib/generators/better_controller/templates/controller.rb
194
+ - lib/generators/better_controller/templates/initializer.rb
195
+ - lib/generators/better_controller/templates/serializer.rb
196
+ - lib/generators/better_controller/templates/service.rb
197
+ - lib/tasks/better_controller_tasks.rake
198
+ - sig/better_controller.rbs
199
+ homepage: https://github.com/alessiobussolari/better_controller
200
+ licenses:
201
+ - MIT
202
+ metadata:
203
+ homepage_uri: https://github.com/alessiobussolari/better_controller
204
+ source_code_uri: https://github.com/alessiobussolari/better_controller
205
+ changelog_uri: https://github.com/alessiobussolari/better_controller/blob/main/CHANGELOG.md
206
+ rubygems_mfa_required: 'true'
207
+ post_install_message:
208
+ rdoc_options: []
209
+ require_paths:
210
+ - lib
211
+ required_ruby_version: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - ">="
214
+ - !ruby/object:Gem::Version
215
+ version: 3.0.0
216
+ required_rubygems_version: !ruby/object:Gem::Requirement
217
+ requirements:
218
+ - - ">="
219
+ - !ruby/object:Gem::Version
220
+ version: '0'
221
+ requirements: []
222
+ rubygems_version: 3.5.11
223
+ signing_key:
224
+ specification_version: 4
225
+ summary: A Ruby gem to enhance Rails controllers with additional functionality
226
+ test_files: []