crudable-rails 1.4.0 → 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.
- checksums.yaml +4 -4
- data/README.md +161 -1
- data/lib/crudable/rails/base.rb +9 -1
- data/lib/crudable/rails/engine.rb +4 -0
- data/lib/crudable/rails/generators/scaffold_controller_extension.rb +55 -0
- data/lib/crudable/rails/generators/scaffold_extension.rb +29 -0
- data/lib/crudable/rails/generators/turbo_forms_generator_option.rb +16 -0
- data/lib/crudable/rails/generators/turbo_forms_scaffold_extension.rb +44 -0
- data/lib/crudable/rails/installer.rb +35 -0
- data/lib/crudable/rails/version.rb +1 -1
- data/lib/crudable-rails.rb +5 -0
- data/lib/generators/crudable/controller/USAGE +23 -0
- data/lib/generators/crudable/controller/controller_generator.rb +19 -0
- data/lib/generators/crudable/controller_helpers.rb +58 -0
- data/lib/generators/crudable/install/USAGE +8 -0
- data/lib/generators/crudable/install/install_generator.rb +19 -0
- data/lib/generators/crudable/scaffold/USAGE +14 -7
- data/lib/generators/crudable/scaffold/scaffold_generator.rb +8 -24
- data/lib/generators/crudable/templates/crudable_controller.rb.tt +257 -0
- data/lib/generators/crudable/templates/turbo_forms/_form.html.erb.tt +37 -0
- data/lib/generators/crudable/templates/turbo_forms/edit.html.erb.tt +14 -0
- data/lib/generators/crudable/templates/turbo_forms/edit.turbo_stream.erb.tt +3 -0
- data/lib/generators/crudable/templates/turbo_forms/new.html.erb.tt +13 -0
- data/lib/generators/crudable/templates/turbo_forms/new.turbo_stream.erb.tt +3 -0
- data/lib/tasks/crudable_tasks.rake +12 -4
- metadata +21 -9
- data/lib/generators/crudable/scaffold/templates/crudable_controller.rb.tt +0 -164
- data/lib/generators/scaffold_controller/USAGE +0 -13
- data/lib/generators/scaffold_controller/scaffold_controller_generator.rb +0 -36
- data/lib/generators/scaffold_controller/templates/crudable_controller.rb.tt +0 -164
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '082ec216ec1a73916737ffc58f6db08819237176efcaceb3b8c3978b5d3667e7'
|
|
4
|
+
data.tar.gz: 4ff9fd3a946d9ee5bb2839d0c41b72eac71a5139f26b87d01c9a608c8fa9204a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 894987edb86a9fd16948ea85009387f8872667bfa2b49b0852193a3277147ffa39186450dcd7632a0984881ca3fea5723e3a024d8516e1ffacea5f2d72a7d50b
|
|
7
|
+
data.tar.gz: 9b3cd6f17af0ef03e9e95186fac23a7fbfd9e9572d079a93c4e1886fc29b112348bc23f0d39476a5b91843c98781035781e4d81b8cf44e506053f1505de854f4
|
data/README.md
CHANGED
|
@@ -30,12 +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
51
|
To use crudable-rails in your controllers, call the `crudable` method.
|
|
38
52
|
|
|
53
|
+
### Generators
|
|
54
|
+
|
|
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
|
|
70
|
+
```
|
|
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
|
+
|
|
39
84
|
## Customizing CRUD Actions
|
|
40
85
|
|
|
41
86
|
You can override the default behavior of CRUD actions by defining the following methods in your controller:
|
|
@@ -83,6 +128,103 @@ By default, Turbo Streams are supported for create, update, and destroy actions.
|
|
|
83
128
|
|
|
84
129
|
This method should return the permitted parameters for the resource as an array. It's required to be defined on all controllers.
|
|
85
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
|
+
|
|
86
228
|
### Optional Private Methods
|
|
87
229
|
|
|
88
230
|
The following private methods are available for use in your controllers:
|
|
@@ -179,7 +321,25 @@ end
|
|
|
179
321
|
|
|
180
322
|
### `(create|update)_params`
|
|
181
323
|
|
|
182
|
-
These methods
|
|
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.
|
|
183
343
|
|
|
184
344
|
## Overriding `authorizable_resource` with a Namespace
|
|
185
345
|
|
data/lib/crudable/rails/base.rb
CHANGED
|
@@ -335,8 +335,16 @@ module Crudable
|
|
|
335
335
|
resource_params
|
|
336
336
|
end
|
|
337
337
|
|
|
338
|
+
def param_method
|
|
339
|
+
@param_method ||= ActionController::Parameters.method_defined?(:expect) ? :expect : :require
|
|
340
|
+
end
|
|
341
|
+
|
|
338
342
|
def resource_params
|
|
339
|
-
|
|
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
|
|
340
348
|
end
|
|
341
349
|
|
|
342
350
|
def permitted_params
|
|
@@ -10,6 +10,10 @@ module Crudable
|
|
|
10
10
|
initializer 'crudable-rails.deprecator' do |app|
|
|
11
11
|
app.deprecators[:crudable_rails] = Crudable::Rails.deprecator
|
|
12
12
|
end
|
|
13
|
+
|
|
14
|
+
initializer 'crudable-rails.generators' do
|
|
15
|
+
require_relative 'generators/scaffold_controller_extension'
|
|
16
|
+
end
|
|
13
17
|
end
|
|
14
18
|
end
|
|
15
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
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'turbo_forms_generator_option'
|
|
4
|
+
require_relative '../../../generators/crudable/controller_helpers'
|
|
5
|
+
|
|
6
|
+
module Crudable
|
|
7
|
+
module Rails
|
|
8
|
+
module Generators
|
|
9
|
+
module TurboFormsScaffoldExtension
|
|
10
|
+
extend ActiveSupport::Concern
|
|
11
|
+
|
|
12
|
+
prepended do
|
|
13
|
+
include TurboFormsGeneratorOption
|
|
14
|
+
include ::Crudable::Generators::ControllerHelpers
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def copy_view_files
|
|
18
|
+
super
|
|
19
|
+
return unless options.turbo_forms?
|
|
20
|
+
|
|
21
|
+
copy_turbo_forms_view_files
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def copy_turbo_forms_view_files
|
|
27
|
+
view_path = File.join('app/views', controller_file_path)
|
|
28
|
+
|
|
29
|
+
template 'turbo_forms/_form.html.erb',
|
|
30
|
+
File.join(view_path, '_form.html.erb'),
|
|
31
|
+
force: true
|
|
32
|
+
|
|
33
|
+
%w[new edit].each do |view|
|
|
34
|
+
template "turbo_forms/#{view}.html.erb",
|
|
35
|
+
File.join(view_path, "#{view}.html.erb"),
|
|
36
|
+
force: true
|
|
37
|
+
template "turbo_forms/#{view}.turbo_stream.erb",
|
|
38
|
+
File.join(view_path, "#{view}.turbo_stream.erb")
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Crudable
|
|
4
|
+
module Rails
|
|
5
|
+
module Installer
|
|
6
|
+
CALLBACK_ACTIONS_FALSE =
|
|
7
|
+
/config\.action_controller\.raise_on_missing_callback_actions\s*=\s*false/
|
|
8
|
+
|
|
9
|
+
module_function
|
|
10
|
+
|
|
11
|
+
def postinstall(root: ::Rails.root)
|
|
12
|
+
environments_path = root.join('config/environments')
|
|
13
|
+
return [] unless environments_path.directory?
|
|
14
|
+
|
|
15
|
+
environments_path.glob('*.rb').filter_map do |file|
|
|
16
|
+
update_raise_on_missing_callback_actions(file)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def update_raise_on_missing_callback_actions(file)
|
|
21
|
+
contents = file.read
|
|
22
|
+
return unless contents.match?(CALLBACK_ACTIONS_FALSE)
|
|
23
|
+
|
|
24
|
+
updated_contents = contents.gsub(
|
|
25
|
+
CALLBACK_ACTIONS_FALSE,
|
|
26
|
+
'config.action_controller.raise_on_missing_callback_actions = true'
|
|
27
|
+
)
|
|
28
|
+
return if updated_contents == contents
|
|
29
|
+
|
|
30
|
+
file.write(updated_contents)
|
|
31
|
+
file.basename.to_s
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
data/lib/crudable-rails.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require 'turbo-rails'
|
|
4
4
|
|
|
5
5
|
require 'crudable/rails/version'
|
|
6
|
+
require 'crudable/rails/installer'
|
|
6
7
|
require 'crudable/rails/engine'
|
|
7
8
|
require 'crudable/rails/controller'
|
|
8
9
|
require 'crudable/rails/base'
|
|
@@ -14,5 +15,9 @@ module Crudable
|
|
|
14
15
|
def self.deprecator
|
|
15
16
|
@deprecator ||= ActiveSupport::Deprecation.new('2.0', 'Crudable::Rails')
|
|
16
17
|
end
|
|
18
|
+
|
|
19
|
+
def self.postinstall(**)
|
|
20
|
+
Installer.postinstall(**)
|
|
21
|
+
end
|
|
17
22
|
end
|
|
18
23
|
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Description:
|
|
2
|
+
Generates a Crudable controller with documented override hooks.
|
|
3
|
+
|
|
4
|
+
Pass the model name, either CamelCased or under_scored. The controller name
|
|
5
|
+
is retrieved as a pluralized version of the model name.
|
|
6
|
+
|
|
7
|
+
To create a controller within a module, specify the model name as a path like
|
|
8
|
+
'parent_module/controller_name'.
|
|
9
|
+
|
|
10
|
+
Example:
|
|
11
|
+
bin/rails generate crudable:controller Post title:string body:text
|
|
12
|
+
|
|
13
|
+
This will create:
|
|
14
|
+
Controller: app/controllers/posts_controller.rb
|
|
15
|
+
|
|
16
|
+
Notes:
|
|
17
|
+
The generated controller includes `crudable` and a `permitted_params` method.
|
|
18
|
+
All other customization hooks are included as commented examples with their
|
|
19
|
+
defaults. Uncomment and tailor as needed.
|
|
20
|
+
|
|
21
|
+
Nested routing is automatically supported: if a parent `*_id` param is present
|
|
22
|
+
and an association exists between the parent and resource, collections and
|
|
23
|
+
resources will be scoped through the parent.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../controller_helpers'
|
|
4
|
+
|
|
5
|
+
module Crudable
|
|
6
|
+
class ControllerGenerator < ::Rails::Generators::NamedBase
|
|
7
|
+
include ::Rails::Generators::ResourceHelpers
|
|
8
|
+
include Crudable::Generators::ControllerHelpers
|
|
9
|
+
|
|
10
|
+
argument :attributes, type: :array, default: [], banner: 'field:type field:type'
|
|
11
|
+
|
|
12
|
+
check_class_collision suffix: 'Controller'
|
|
13
|
+
|
|
14
|
+
def create_controller_file
|
|
15
|
+
template 'crudable_controller.rb',
|
|
16
|
+
File.join('app/controllers', controller_class_path, "#{controller_file_name}_controller.rb")
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Crudable
|
|
4
|
+
module Generators
|
|
5
|
+
module ControllerHelpers
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
class_methods do
|
|
9
|
+
def crudable_template_root
|
|
10
|
+
@crudable_template_root ||= File.expand_path('templates', __dir__)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
included do
|
|
15
|
+
source_paths << crudable_template_root
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def permitted_params_list
|
|
21
|
+
attachments, others = attributes_names.partition { |name| attachments?(name) }
|
|
22
|
+
params = others.map { |name| ":#{name}" }
|
|
23
|
+
params += attachments.map { |name| "#{name}: []" }
|
|
24
|
+
params.join(', ')
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def attachments?(name)
|
|
28
|
+
attribute = attributes.find { |attr| attr.name == name }
|
|
29
|
+
attribute&.attachments?
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def reference_attributes
|
|
33
|
+
attributes.select { |attr| attr.respond_to?(:reference?) && attr.reference? }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def form_attributes
|
|
37
|
+
return attributes if reference_attributes.empty?
|
|
38
|
+
|
|
39
|
+
attributes.reject { |attr| attr.respond_to?(:reference?) && attr.reference? }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def form_with_model
|
|
43
|
+
segments = []
|
|
44
|
+
segments.concat(controller_class_path.map { |namespace| ":#{namespace}" }) if controller_class_path.any?
|
|
45
|
+
|
|
46
|
+
reference_attributes.each do |attribute|
|
|
47
|
+
segments << "@#{attribute.name}"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
segments << "@#{singular_table_name}"
|
|
51
|
+
|
|
52
|
+
return segments.first if segments.size == 1
|
|
53
|
+
|
|
54
|
+
"[#{segments.join(', ')}]"
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
Description:
|
|
2
|
+
Installs crudable-rails configuration in the host application.
|
|
3
|
+
|
|
4
|
+
Example:
|
|
5
|
+
bin/rails generate crudable:install
|
|
6
|
+
|
|
7
|
+
This will set config.action_controller.raise_on_missing_callback_actions
|
|
8
|
+
to true in any environment file that currently sets it to false.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Crudable
|
|
4
|
+
module Generators
|
|
5
|
+
class InstallGenerator < ::Rails::Generators::Base
|
|
6
|
+
desc 'Install crudable-rails configuration'
|
|
7
|
+
|
|
8
|
+
def postinstall
|
|
9
|
+
updated = ::Crudable::Rails::Installer.postinstall
|
|
10
|
+
|
|
11
|
+
if updated.any?
|
|
12
|
+
say "Set raise_on_missing_callback_actions to true in: #{updated.join(', ')}", :green
|
|
13
|
+
else
|
|
14
|
+
say 'No environment files with raise_on_missing_callback_actions = false were found.', :yellow
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
Description:
|
|
2
|
-
Generates a Rails scaffold
|
|
2
|
+
Generates a full Rails scaffold (model, migration, views, routes, tests) with a
|
|
3
|
+
Crudable controller instead of the default scaffold controller.
|
|
4
|
+
|
|
5
|
+
Pass the model name, either CamelCased or under_scored, and optional attributes.
|
|
3
6
|
|
|
4
7
|
Example:
|
|
5
|
-
bin/rails generate crudable:scaffold
|
|
8
|
+
bin/rails generate crudable:scaffold Post title:string body:text
|
|
9
|
+
bin/rails generate crudable:scaffold Post title:string body:text --turbo-forms
|
|
10
|
+
|
|
11
|
+
This will create the same files as `rails generate scaffold`, but the controller
|
|
12
|
+
will use `crudable` with documented override hooks.
|
|
6
13
|
|
|
7
|
-
|
|
8
|
-
|
|
14
|
+
With --turbo-forms, new and edit views wrap the form partial in a dom_id target
|
|
15
|
+
and generate matching turbo_stream templates for validation error responses.
|
|
9
16
|
|
|
10
17
|
Notes:
|
|
11
|
-
Nested routing is automatically supported: if a parent `*_id` param is present
|
|
12
|
-
exists between the parent and resource, collections and
|
|
13
|
-
|
|
18
|
+
Nested routing is automatically supported: if a parent `*_id` param is present
|
|
19
|
+
and an association exists between the parent and resource, collections and
|
|
20
|
+
resources will be scoped through the parent.
|
|
@@ -1,32 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
include Rails::Generators::ResourceHelpers
|
|
6
|
-
|
|
7
|
-
source_root File.expand_path('templates', __dir__)
|
|
8
|
-
|
|
9
|
-
argument :attributes, type: :array, default: [], banner: 'field:type field:type'
|
|
3
|
+
require 'rails/generators/rails/scaffold/scaffold_generator'
|
|
4
|
+
require_relative '../controller_helpers'
|
|
10
5
|
|
|
11
|
-
|
|
6
|
+
module Crudable
|
|
7
|
+
class ScaffoldGenerator < ::Rails::Generators::ScaffoldGenerator
|
|
8
|
+
include Crudable::Generators::ControllerHelpers
|
|
12
9
|
|
|
13
|
-
def
|
|
10
|
+
def crudable_controller
|
|
14
11
|
template 'crudable_controller.rb',
|
|
15
|
-
File.join('app/controllers', controller_class_path, "#{controller_file_name}_controller.rb"),
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
private
|
|
19
|
-
|
|
20
|
-
def permitted_params
|
|
21
|
-
attachments, others = attributes_names.partition { |name| attachments?(name) }
|
|
22
|
-
params = others.map { |name| ":#{name}" }
|
|
23
|
-
params += attachments.map { |name| "#{name}: []" }
|
|
24
|
-
params.join(', ')
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def attachments?(name)
|
|
28
|
-
attribute = attributes.find { |attr| attr.name == name }
|
|
29
|
-
attribute&.attachments?
|
|
12
|
+
File.join('app/controllers', controller_class_path, "#{controller_file_name}_controller.rb"),
|
|
13
|
+
force: true
|
|
30
14
|
end
|
|
31
15
|
end
|
|
32
16
|
end
|