crudable-rails 1.3 → 1.5.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 (30) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +194 -10
  3. data/Rakefile +4 -2
  4. data/lib/crudable/rails/base.rb +133 -19
  5. data/lib/crudable/rails/controller.rb +1 -2
  6. data/lib/crudable/rails/engine.rb +7 -1
  7. data/lib/crudable/rails/generators/scaffold_controller_extension.rb +55 -0
  8. data/lib/crudable/rails/generators/scaffold_extension.rb +29 -0
  9. data/lib/crudable/rails/generators/turbo_forms_generator_option.rb +16 -0
  10. data/lib/crudable/rails/generators/turbo_forms_scaffold_extension.rb +44 -0
  11. data/lib/crudable/rails/installer.rb +35 -0
  12. data/lib/crudable/rails/nestable.rb +78 -9
  13. data/lib/crudable/rails/resourceable.rb +29 -3
  14. data/lib/crudable/rails/version.rb +1 -1
  15. data/lib/crudable-rails.rb +8 -1
  16. data/lib/generators/crudable/controller/USAGE +23 -0
  17. data/lib/generators/crudable/controller/controller_generator.rb +19 -0
  18. data/lib/generators/crudable/controller_helpers.rb +58 -0
  19. data/lib/generators/crudable/install/USAGE +8 -0
  20. data/lib/generators/crudable/install/install_generator.rb +19 -0
  21. data/lib/generators/crudable/scaffold/USAGE +20 -0
  22. data/lib/generators/crudable/scaffold/scaffold_generator.rb +16 -0
  23. data/lib/generators/crudable/templates/crudable_controller.rb.tt +257 -0
  24. data/lib/generators/crudable/templates/turbo_forms/_form.html.erb.tt +37 -0
  25. data/lib/generators/crudable/templates/turbo_forms/edit.html.erb.tt +14 -0
  26. data/lib/generators/crudable/templates/turbo_forms/edit.turbo_stream.erb.tt +3 -0
  27. data/lib/generators/crudable/templates/turbo_forms/new.html.erb.tt +13 -0
  28. data/lib/generators/crudable/templates/turbo_forms/new.turbo_stream.erb.tt +3 -0
  29. data/lib/tasks/crudable_tasks.rake +14 -4
  30. metadata +35 -16
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 55f8eea5d65ce4caa175212c791a16bf9513306f54924b859868f6e62dba4011
4
- data.tar.gz: 5fad24b510a2b29ab90b77e784b06cf114cb54fb11001dbb582bb2353ba02ac1
3
+ metadata.gz: '082ec216ec1a73916737ffc58f6db08819237176efcaceb3b8c3978b5d3667e7'
4
+ data.tar.gz: 4ff9fd3a946d9ee5bb2839d0c41b72eac71a5139f26b87d01c9a608c8fa9204a
5
5
  SHA512:
6
- metadata.gz: 4e0242ef6e4a90c2b83f5cfdfd535776f7ec233c227f88d1e6ec2d39d6d9bd766ae8e650b452078d72c30327d3de94a2ac965f3dfa0d988e53a4fc2be6add0d2
7
- data.tar.gz: 4af78bf8f8ffe06a7ca77f46b34c746db1d137ad53788af62434347db7d7a4769c7b0f4577d9087a368ef215145c92936087d2b26dd96f7912e74467aa5a7479
6
+ metadata.gz: 894987edb86a9fd16948ea85009387f8872667bfa2b49b0852193a3277147ffa39186450dcd7632a0984881ca3fea5723e3a024d8516e1ffacea5f2d72a7d50b
7
+ data.tar.gz: 9b3cd6f17af0ef03e9e95186fac23a7fbfd9e9572d079a93c4e1886fc29b112348bc23f0d39476a5b91843c98781035781e4d81b8cf44e506053f1505de854f4
data/README.md CHANGED
@@ -30,22 +30,57 @@ Or install it yourself as:
30
30
  $ gem install crudable-rails
31
31
  ```
32
32
 
33
+ Then run the install generator in your Rails application:
34
+
35
+ ```bash
36
+ bin/rails generate crudable:install
37
+ ```
38
+
39
+ This sets `config.action_controller.raise_on_missing_callback_actions` to `true` in any environment file under `config/environments/` that currently sets it to `false`. Crudable controllers rely on `before_action` callbacks; enabling this setting helps catch invalid `only` / `except` options early in development and test.
40
+
41
+ You can also run the same step as a Rake task:
42
+
43
+ ```bash
44
+ bin/rails crudable:install
45
+ ```
46
+
33
47
  ## Usage
34
48
 
35
49
  ### Controller Setup
36
50
 
37
- To use crudable-rails in your controllers, call the `crudable` method. You can also specify if the controller is nested by passing the `nested: true` option.
51
+ To use crudable-rails in your controllers, call the `crudable` method.
38
52
 
39
- ```ruby
40
- class ProductsController < ApplicationController
41
- crudable
42
- end
53
+ ### Generators
43
54
 
44
- class ProductSizesController < ApplicationController
45
- crudable nested: true
46
- end
55
+ The gem ships Rails generators to scaffold resources with a Crudable controller. Generated controllers include `crudable`, a `permitted_params` method, and commented examples of every override hook with its default implementation — uncomment and tailor as needed.
56
+
57
+ **Full scaffold** — model, migration, views, routes, tests, and a Crudable controller (same output as `rails generate scaffold`, but with a Crudable controller):
58
+
59
+ ```bash
60
+ bin/rails generate crudable:scaffold Post title:string body:text
61
+ bin/rails generate crudable:scaffold Post title:string body:text --turbo-forms
62
+ ```
63
+
64
+ With `--turbo-forms`, generated `new` and `edit` views wrap the `_form` partial in a `dom_id(record, :form)` target and add matching `new.turbo_stream.erb` / `edit.turbo_stream.erb` templates. Failed create/update actions rendered by crudable will replace that form partial with validation errors inline.
65
+
66
+ **Controller only** — when you already have a model and views, or want to wire up the controller yourself:
67
+
68
+ ```bash
69
+ bin/rails generate crudable:controller Post title:string body:text
47
70
  ```
48
71
 
72
+ You can also pass `--crudable` to the built-in Rails generators:
73
+
74
+ ```bash
75
+ bin/rails generate scaffold Post title:string body:text --crudable
76
+ bin/rails generate scaffold Post title:string body:text --crudable --turbo-forms
77
+ bin/rails generate scaffold_controller Post title:string body:text --crudable
78
+ ```
79
+
80
+ Use `rails generate scaffold` without `--crudable` when you want the standard Rails scaffold controller.
81
+
82
+ Nested routing is supported automatically: when a parent `*_id` param is present and an association exists between the parent and resource, collections and member actions are scoped through the parent.
83
+
49
84
  ## Customizing CRUD Actions
50
85
 
51
86
  You can override the default behavior of CRUD actions by defining the following methods in your controller:
@@ -93,6 +128,103 @@ By default, Turbo Streams are supported for create, update, and destroy actions.
93
128
 
94
129
  This method should return the permitted parameters for the resource as an array. It's required to be defined on all controllers.
95
130
 
131
+ The example below uses a `Product` with a `has_many :product_sizes` association and `accepts_nested_attributes_for`:
132
+
133
+ ```ruby
134
+ # app/models/product.rb
135
+ class Product < ApplicationRecord
136
+ has_many :product_sizes
137
+ accepts_nested_attributes_for :product_sizes, allow_destroy: true
138
+ end
139
+
140
+ # app/controllers/products_controller.rb
141
+ class ProductsController < ApplicationController
142
+ crudable
143
+
144
+ private
145
+
146
+ def permitted_params
147
+ [:name, product_sizes_attributes: [[:id, :name, :_destroy]]]
148
+ end
149
+ end
150
+ ```
151
+
152
+ A typical request payload for create/update looks like:
153
+
154
+ ```json
155
+ {
156
+ "product": {
157
+ "name": "T-shirt",
158
+ "product_sizes_attributes": {
159
+ "0": { "name": "Small" },
160
+ "1": { "id": "42", "name": "Medium" },
161
+ "2": { "id": "43", "_destroy": "1" }
162
+ }
163
+ }
164
+ }
165
+ ```
166
+
167
+ For `has_many` nested attributes, Rails 8 `expect` requires **double array brackets** — an array wrapped in an array — to declare that each nested record is a hash (`[[:id, :name, :_destroy]]`). This form also works with `require.permit` on hash-style payloads from `fields_for` / `accepts_nested_attributes_for`, so the same `permitted_params` definition works on both Rails versions.
168
+
169
+ ### `param_method`
170
+
171
+ Controls how strong parameters are required and permitted in `resource_params`. On **Rails 8+**, the default is `:expect`, which uses `params.expect` to require and permit in a single step. On earlier Rails versions, it falls back to `:require` (`params.require(...).permit(...)`).
172
+
173
+ **Rails 8 (default — `:expect`)**
174
+
175
+ ```ruby
176
+ class ProductsController < ApplicationController
177
+ crudable
178
+
179
+ private
180
+
181
+ def permitted_params
182
+ [:name, product_sizes_attributes: [[:id, :name, :_destroy]]]
183
+ end
184
+ end
185
+
186
+ # resource_params is equivalent to:
187
+ # params.expect(product: [:name, product_sizes_attributes: [[:id, :name, :_destroy]]])
188
+ ```
189
+
190
+ **Rails 7 and earlier (default — `:require`)**
191
+
192
+ ```ruby
193
+ class ProductsController < ApplicationController
194
+ crudable
195
+
196
+ private
197
+
198
+ def permitted_params
199
+ [:name, product_sizes_attributes: [[:id, :name, :_destroy]]]
200
+ end
201
+ end
202
+
203
+ # resource_params is equivalent to:
204
+ # params.require(:product).permit(:name, product_sizes_attributes: [[:id, :name, :_destroy]])
205
+ ```
206
+
207
+ **Override to use `require` on Rails 8**
208
+
209
+ ```ruby
210
+ class ProductsController < ApplicationController
211
+ crudable
212
+
213
+ private
214
+
215
+ def param_method
216
+ :require
217
+ end
218
+
219
+ def permitted_params
220
+ [:name, product_sizes_attributes: [[:id, :name, :_destroy]]]
221
+ end
222
+ end
223
+
224
+ # resource_params is equivalent to:
225
+ # params.require(:product).permit(:name, product_sizes_attributes: [[:id, :name, :_destroy]])
226
+ ```
227
+
96
228
  ### Optional Private Methods
97
229
 
98
230
  The following private methods are available for use in your controllers:
@@ -137,6 +269,14 @@ This method should return a boolean value to determine if the resource should be
137
269
 
138
270
  This method should return a boolean value to determine if the resource is a singleton. Default: `false`.
139
271
 
272
+ ### `use_parent_as_scope?`
273
+
274
+ This method should return a boolean value to determine if the resource should be found using the nested parent. Default: `true`.
275
+
276
+ ### `parent_id_param`
277
+
278
+ When using nested routes, this determines which `*_id` param is treated as the parent id. If multiple `*_id` params are present (multi-level nesting), Crudable will default to the **deepest/last** `*_id` from the route path parameters.
279
+
140
280
  ### `finder_param`
141
281
 
142
282
  This method should return the parameter used to find the resource. Default: `:id`.
@@ -147,15 +287,59 @@ This method should return a boolean value to determine if the resource should be
147
287
 
148
288
  ### `friendly_finders?`
149
289
 
150
- This method should return a boolean value to determine if the resource should be found using friendly finders. Default: `true` if FriendlyId is available, otherwise `false`.
290
+ This method should return a boolean value to determine if the resource should be found using friendly finders.
291
+
292
+ Default: `true` when `FriendlyId` is available **and** the model responds to `.friendly`, otherwise `false`.
293
+
294
+ ### `parent_friendly_finders?`
295
+
296
+ When using nested routes (e.g. `/:parent_id/:id`), this method controls whether the **parent** should be found using FriendlyId.
297
+
298
+ Default: `friendly_finders?` (and additionally requires `FriendlyId` to be defined and the parent model to respond to `.friendly`).
151
299
 
152
300
  ### `skip_initialize_create?`
153
301
 
154
302
  This method should return a boolean value to determine if the resource should be initialized on create. Default: `false`.
155
303
 
304
+ ### `authorize_with_pundit?`
305
+
306
+ This method controls whether Pundit authorization should be performed. By default, it returns `true` when Pundit is defined. You can override this method to customize authorization behavior based on feature flags, user roles, or other conditions.
307
+
308
+ For example:
309
+
310
+ ```ruby
311
+ class ProductsController < ApplicationController
312
+ crudable
313
+
314
+ private
315
+
316
+ def authorize_with_pundit?
317
+ super && current_user.present? && feature_enabled?(:authorization)
318
+ end
319
+ end
320
+ ```
321
+
156
322
  ### `(create|update)_params`
157
323
 
158
- These methods should return the permitted parameters for the resource as an array. They are optional and can be defined if create and update methods need different parameters allowed.
324
+ These methods delegate to `resource_params` by default. Override them when create and update actions need different permitted parameters for example, allowing new sizes on create but only updates and destroys on update:
325
+
326
+ ```ruby
327
+ class ProductsController < ApplicationController
328
+ crudable
329
+
330
+ private
331
+
332
+ def create_params
333
+ params.expect(product: [:name, product_sizes_attributes: [[:name]]])
334
+ end
335
+
336
+ def update_params
337
+ params.expect(product: [:name, product_sizes_attributes: [[:id, :name, :_destroy]]])
338
+ end
339
+ end
340
+ ```
341
+
342
+ See `param_method` and `permitted_params` for the default strong-parameter handling.
159
343
 
160
344
  ## Overriding `authorizable_resource` with a Namespace
161
345
 
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
- require "bundler/setup"
1
+ # frozen_string_literal: true
2
2
 
3
- require "bundler/gem_tasks"
3
+ require 'bundler/setup'
4
+
5
+ require 'bundler/gem_tasks'
@@ -5,47 +5,76 @@ module Crudable
5
5
  module Base
6
6
  extend ActiveSupport::Concern
7
7
 
8
+ # Status code for unprocessable entity (422)
9
+ # Rails 7.1+ uses :unprocessable_content (replaces deprecated :unprocessable_entity)
10
+ UNPROCESSABLE_STATUS = :unprocessable_content
11
+
8
12
  included do
9
13
  include Crudable::Rails::Resourceable
14
+ include Crudable::Rails::Nestable
10
15
 
11
16
  before_action :find_resource, only: %i[show edit update destroy]
12
- before_action :authorize_class_action, only: %i[index] if defined?(Pundit)
13
- after_action :authorize_resource, only: %i[new show edit] if defined?(Pundit)
14
17
 
15
18
  decorates_assigned plural_resource_var_name.to_sym, resource_var_name.to_sym if defined?(Draper)
16
19
  end
17
20
 
18
21
  def index
22
+ authorize_class_action if authorize_with_pundit?
19
23
  instance_variable_set("@#{plural_resource_var_name}", resource_scope)
20
24
  paginate_resource
21
25
  end
22
26
 
23
- def show; end
27
+ def show
28
+ render_not_found if instance_variable_get("@#{resource_var_name}").blank?
29
+ authorize_resource if authorize_with_pundit?
30
+ end
24
31
 
25
32
  def new
26
- instance_variable_set("@#{resource_var_name}", resource_class.new)
33
+ instance = new_instance
34
+ # Ensure we always set a valid instance to prevent nil model warnings in Rails 8
35
+ raise ActiveRecord::RecordNotFound, "Could not create new #{resource_class.name}" if instance.nil?
36
+
37
+ instance_variable_set("@#{resource_var_name}", instance)
38
+ authorize_resource if authorize_with_pundit?
27
39
  end
28
40
 
29
- def create # rubocop:disable Metrics/MethodLength
30
- instance_variable_set("@#{resource_var_name}", resource_class.new(create_params)) unless skip_initialize_create?
31
- if defined?(Pundit)
41
+ def create
42
+ unless skip_initialize_create?
43
+ instance_variable_set("@#{resource_var_name}", new_instance)
44
+ instance_variable_get("@#{resource_var_name}").assign_attributes(create_params)
45
+ end
46
+ resource = instance_variable_get("@#{resource_var_name}")
47
+ # If skip_initialize_create? is true, resource might be nil - that's expected
48
+ # Only return 404 if we tried to initialize but resource is still nil
49
+ return render_not_found if resource.nil? && !skip_initialize_create?
50
+
51
+ # Only authorize if resource exists (skip authorization when skip_initialize_create? is true)
52
+ if authorize_with_pundit? && resource.present?
32
53
  before_authorize_create
33
54
  authorize_resource
34
55
  after_authorize_create
56
+ elsif authorize_with_pundit?
57
+ skip_authorization
35
58
  end
36
- if instance_variable_get("@#{resource_var_name}").save
59
+ if resource&.save
37
60
  on_successful_create
38
61
  on_successful_create_render
39
62
  else
40
63
  on_failed_create_setup
41
64
  on_failed_create_render
42
65
  end
66
+ rescue ActionController::ParameterMissing
67
+ head :bad_request
43
68
  end
44
69
 
45
- def edit; end
70
+ def edit
71
+ render_not_found if instance_variable_get("@#{resource_var_name}").blank?
72
+ authorize_resource if authorize_with_pundit?
73
+ end
46
74
 
47
75
  def update
48
- if defined?(Pundit)
76
+ render_not_found if instance_variable_get("@#{resource_var_name}").blank?
77
+ if authorize_with_pundit?
49
78
  before_authorize_update
50
79
  authorize_resource
51
80
  after_authorize_update
@@ -57,10 +86,12 @@ module Crudable
57
86
  on_failed_update_setup
58
87
  on_failed_update_render
59
88
  end
89
+ rescue ActionController::ParameterMissing
90
+ head :bad_request
60
91
  end
61
92
 
62
93
  def destroy
63
- authorize_resource(destroy_method) if defined?(Pundit)
94
+ authorize_resource(destroy_method) if authorize_with_pundit?
64
95
  if instance_variable_get("@#{resource_var_name}").send(destroy_method)
65
96
  on_successful_destroy
66
97
  on_successful_destroy_render
@@ -72,6 +103,10 @@ module Crudable
72
103
 
73
104
  private
74
105
 
106
+ def authorize_with_pundit?
107
+ defined?(Pundit)
108
+ end
109
+
75
110
  def destroy_method
76
111
  return :destroy unless defined?(Discard)
77
112
  return :destroy if params[:destroy]
@@ -85,11 +120,38 @@ module Crudable
85
120
 
86
121
  def find_resource
87
122
  resource = friendly_finders? ? resource_class.friendly : resource_class
88
- instance = singleton? ? resource.first : resource.find(params[finder_param])
123
+ instance = find_instance(resource)
89
124
 
90
125
  return redirect_to (resource_namespace + [instance]), status: :moved_permanently if should_redirect?(instance)
91
126
 
92
127
  instance_variable_set("@#{resource_var_name}", instance)
128
+ rescue ActiveRecord::RecordNotFound
129
+ render_not_found
130
+ end
131
+
132
+ def find_instance(resource)
133
+ if singleton?
134
+ resource.first
135
+ elsif parent_resource_association.present?
136
+ scope = instance_variable_get("@#{parent_var_name}").send(parent_resource_association)
137
+ scope = scope.friendly if friendly_finders?
138
+ scope.find(params[finder_param])
139
+ else
140
+ resource.find(params[finder_param])
141
+ end
142
+ end
143
+
144
+ def new_instance
145
+ if parent_resource_association.present?
146
+ parent = instance_variable_get("@#{parent_var_name}")
147
+ # If parent is nil, it means find_parent failed - this shouldn't happen
148
+ # but we guard against it to prevent nil errors
149
+ raise ActiveRecord::RecordNotFound, "Parent #{parent_var_name} not found" if parent.nil?
150
+
151
+ parent.send(parent_resource_association).new
152
+ else
153
+ resource_class.new
154
+ end
93
155
  end
94
156
 
95
157
  def should_redirect?(instance)
@@ -111,7 +173,27 @@ module Crudable
111
173
  end
112
174
 
113
175
  def authorizable_scope
114
- defined?(Pundit) ? policy_scope(resource_namespace + [resource_class]) : resource_class.all
176
+ scope = find_scope
177
+ return scope.all unless authorize_with_pundit?
178
+ # Check if Pundit::Authorization is available
179
+ return scope.all unless if respond_to?(:pundit_authorization_available?,
180
+ true)
181
+ pundit_authorization_available?
182
+ else
183
+ self.class.included_modules.include?(Pundit::Authorization) || respond_to?(
184
+ :policy_scope, true
185
+ )
186
+ end
187
+
188
+ policy_scope(resource_namespace + [scope])
189
+ end
190
+
191
+ def find_scope
192
+ if parent_resource_association.present?
193
+ instance_variable_get("@#{parent_var_name}").send(parent_resource_association)
194
+ else
195
+ resource_class
196
+ end
115
197
  end
116
198
 
117
199
  def paginate_resource?
@@ -140,6 +222,14 @@ module Crudable
140
222
  end
141
223
 
142
224
  def after_create_redirect_path
225
+ if respond_to?(:parent_present?) && parent_present? && instance_variable_get("@#{parent_var_name}")
226
+ parent = instance_variable_get("@#{parent_var_name}")
227
+ resource_namespace + [parent, plural_resource_var_name.to_sym]
228
+ else
229
+ resource_namespace + [plural_resource_var_name.to_sym]
230
+ end
231
+ rescue NoMethodError
232
+ # Fallback if parent_present? or parent_var_name methods aren't available
143
233
  resource_namespace + [plural_resource_var_name.to_sym]
144
234
  end
145
235
 
@@ -216,16 +306,24 @@ module Crudable
216
306
  def after_authorize_update; end
217
307
 
218
308
  def on_failed_create_render
309
+ # Ensure resource is set before rendering the new template
310
+ # This prevents Rails 8 deprecation warnings about nil model arguments
311
+ resource = instance_variable_get("@#{resource_var_name}")
312
+ if resource.nil?
313
+ # Always initialize for rendering, even if skip_initialize_create? is true
314
+ # The skip_initialize_create? flag only affects the create action, not rendering
315
+ instance_variable_set("@#{resource_var_name}", new_instance)
316
+ end
219
317
  respond_to do |format|
220
318
  format.turbo_stream { render_action(:new) }
221
- format.html { render :new, status: :unprocessable_entity }
319
+ format.html { render :new, status: UNPROCESSABLE_STATUS }
222
320
  end
223
321
  end
224
322
 
225
323
  def on_failed_update_render
226
324
  respond_to do |format|
227
325
  format.turbo_stream { render_action(:edit) }
228
- format.html { render :edit, status: :unprocessable_entity }
326
+ format.html { render :edit, status: UNPROCESSABLE_STATUS }
229
327
  end
230
328
  end
231
329
 
@@ -237,8 +335,16 @@ module Crudable
237
335
  resource_params
238
336
  end
239
337
 
338
+ def param_method
339
+ @param_method ||= ActionController::Parameters.method_defined?(:expect) ? :expect : :require
340
+ end
341
+
240
342
  def resource_params
241
- params.require(resource_var_name).permit(*permitted_params)
343
+ if param_method == :expect
344
+ params.send(param_method, resource_var_name.to_sym => permitted_params)
345
+ else
346
+ params.send(param_method, resource_var_name).permit(*permitted_params)
347
+ end
242
348
  end
243
349
 
244
350
  def permitted_params
@@ -246,14 +352,22 @@ module Crudable
246
352
  end
247
353
 
248
354
  def render_action(default_action_name)
249
- logger.debug "Rendering relevant action for #{controller_path}/#{default_action_name} as #{request.format.symbol}"
250
- return render default_action_name if lookup_context.template_exists?("#{controller_path}/#{default_action_name}")
355
+ logger.debug "Rendering relevant action for #{controller_path}/#{default_action_name} " \
356
+ "as #{request.format.symbol}"
357
+ if lookup_context.template_exists?("#{controller_path}/#{default_action_name}")
358
+ return render default_action_name
359
+ end
251
360
 
252
- Crudable::Rails.deprecator.warn("Rendering fallback: #{action_name}, format: #{request.format.symbol}. Rename your template to #{default_action_name}")
361
+ Crudable::Rails.deprecator.warn("Rendering fallback: #{action_name}, format: #{request.format.symbol}. " \
362
+ "Rename your template to #{default_action_name}")
253
363
 
254
364
  logger.debug "Rendering fallback: #{action_name}"
255
365
  render
256
366
  end
367
+
368
+ def render_not_found
369
+ head :not_found
370
+ end
257
371
  end
258
372
  end
259
373
  end
@@ -7,9 +7,8 @@ module Crudable
7
7
  extend ActiveSupport::Concern
8
8
 
9
9
  class_methods do
10
- def crudable(nested: false)
10
+ def crudable
11
11
  include Crudable::Rails::Base
12
- include Crudable::Rails::Nestable if nested
13
12
  end
14
13
  end
15
14
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Crudable
2
4
  module Rails
3
5
  class Engine < ::Rails::Engine
@@ -5,9 +7,13 @@ module Crudable
5
7
  ::ActionController::Base.include Crudable::Rails::Controller
6
8
  end
7
9
 
8
- initializer "crudable-rails.deprecator" do |app|
10
+ initializer 'crudable-rails.deprecator' do |app|
9
11
  app.deprecators[:crudable_rails] = Crudable::Rails.deprecator
10
12
  end
13
+
14
+ initializer 'crudable-rails.generators' do
15
+ require_relative 'generators/scaffold_controller_extension'
16
+ end
11
17
  end
12
18
  end
13
19
  end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../generators/crudable/controller_helpers'
4
+ require_relative 'turbo_forms_generator_option'
5
+
6
+ module Crudable
7
+ module Rails
8
+ module Generators
9
+ module ScaffoldControllerExtension
10
+ extend ActiveSupport::Concern
11
+
12
+ prepended do
13
+ include TurboFormsGeneratorOption
14
+ include ::Crudable::Generators::ControllerHelpers
15
+
16
+ class_option :crudable, type: :boolean, default: false,
17
+ desc: 'Generate with crudable controller'
18
+ end
19
+
20
+ def create_controller_files
21
+ return super unless options.crudable?
22
+
23
+ template 'crudable_controller.rb',
24
+ File.join('app/controllers', controller_class_path, "#{controller_file_name}_controller.rb")
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ Rails.application.config.after_initialize do
32
+ require 'rails/generators'
33
+ require 'rails/generators/named_base'
34
+ require 'rails/generators/resource_helpers'
35
+ require 'rails/generators/erb/scaffold/scaffold_generator'
36
+ require 'rails/generators/rails/scaffold_controller/scaffold_controller_generator'
37
+ require 'rails/generators/rails/scaffold/scaffold_generator'
38
+ require_relative 'scaffold_extension'
39
+ require_relative 'turbo_forms_scaffold_extension'
40
+
41
+ unless Rails::Generators::ScaffoldControllerGenerator
42
+ .ancestors.include?(Crudable::Rails::Generators::ScaffoldControllerExtension)
43
+ Rails::Generators::ScaffoldControllerGenerator.prepend Crudable::Rails::Generators::ScaffoldControllerExtension
44
+ end
45
+
46
+ unless Rails::Generators::ScaffoldGenerator
47
+ .included_modules.include?(Crudable::Rails::Generators::ScaffoldExtension)
48
+ Rails::Generators::ScaffoldGenerator.include Crudable::Rails::Generators::ScaffoldExtension
49
+ end
50
+
51
+ unless Erb::Generators::ScaffoldGenerator
52
+ .ancestors.include?(Crudable::Rails::Generators::TurboFormsScaffoldExtension)
53
+ Erb::Generators::ScaffoldGenerator.prepend Crudable::Rails::Generators::TurboFormsScaffoldExtension
54
+ end
55
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'turbo_forms_generator_option'
4
+
5
+ module Crudable
6
+ module Rails
7
+ module Generators
8
+ module ScaffoldExtension
9
+ extend ActiveSupport::Concern
10
+
11
+ included do
12
+ include TurboFormsGeneratorOption
13
+ include ::Crudable::Generators::ControllerHelpers
14
+
15
+ class_option :crudable, type: :boolean, default: false,
16
+ desc: 'Generate with crudable controller'
17
+ end
18
+
19
+ def crudable_controller
20
+ return unless options.crudable?
21
+
22
+ template 'crudable_controller.rb',
23
+ File.join('app/controllers', controller_class_path, "#{controller_file_name}_controller.rb"),
24
+ force: true
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Crudable
4
+ module Rails
5
+ module Generators
6
+ module TurboFormsGeneratorOption
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ class_option :turbo_forms, type: :boolean, default: false,
11
+ desc: 'Generate turbo stream form templates for new and edit actions'
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end