crudable-rails 1.2.1 → 1.4.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 +36 -12
- data/Rakefile +4 -2
- data/lib/crudable/rails/base.rb +124 -17
- data/lib/crudable/rails/controller.rb +1 -2
- data/lib/crudable/rails/engine.rb +3 -1
- data/lib/crudable/rails/nestable.rb +78 -9
- data/lib/crudable/rails/resourceable.rb +32 -2
- data/lib/crudable/rails/version.rb +1 -1
- data/lib/crudable-rails.rb +3 -1
- data/lib/generators/crudable/scaffold/USAGE +13 -0
- data/lib/generators/crudable/scaffold/scaffold_generator.rb +32 -0
- data/lib/generators/crudable/scaffold/templates/crudable_controller.rb.tt +164 -0
- data/lib/generators/scaffold_controller/USAGE +13 -0
- data/lib/generators/scaffold_controller/scaffold_controller_generator.rb +36 -0
- data/lib/generators/scaffold_controller/templates/crudable_controller.rb.tt +164 -0
- data/lib/tasks/crudable_tasks.rake +2 -0
- metadata +23 -19
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6eb33d21180100aca344bcdc68bb1c170e28bff416b95c3bb4332fcb7c1eef16
|
|
4
|
+
data.tar.gz: a08037ec9a25220ba87697becdc928bf78400240088fb1f4c5157730dbfae162
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ec33c0349fa255e003542bd431b5a84ea4b49ca981713409f372655944158dc9656070499d67c915d6dfb70e635136f736310ce84522bfa4e268b94bfb879896
|
|
7
|
+
data.tar.gz: 2226bedef0b794653978bfd8deab2302d2023909857de65bbec4e600df3a545a171a2c9575271a3a8ca1e6041f3fdec9b86fc1775dcf2dc6d65fd543057ccf84
|
data/README.md
CHANGED
|
@@ -34,17 +34,7 @@ $ gem install crudable-rails
|
|
|
34
34
|
|
|
35
35
|
### Controller Setup
|
|
36
36
|
|
|
37
|
-
To use crudable-rails in your controllers, call the `crudable` method.
|
|
38
|
-
|
|
39
|
-
```ruby
|
|
40
|
-
class ProductsController < ApplicationController
|
|
41
|
-
crudable
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
class ProductSizesController < ApplicationController
|
|
45
|
-
crudable nested: true
|
|
46
|
-
end
|
|
47
|
-
```
|
|
37
|
+
To use crudable-rails in your controllers, call the `crudable` method.
|
|
48
38
|
|
|
49
39
|
## Customizing CRUD Actions
|
|
50
40
|
|
|
@@ -137,6 +127,14 @@ This method should return a boolean value to determine if the resource should be
|
|
|
137
127
|
|
|
138
128
|
This method should return a boolean value to determine if the resource is a singleton. Default: `false`.
|
|
139
129
|
|
|
130
|
+
### `use_parent_as_scope?`
|
|
131
|
+
|
|
132
|
+
This method should return a boolean value to determine if the resource should be found using the nested parent. Default: `true`.
|
|
133
|
+
|
|
134
|
+
### `parent_id_param`
|
|
135
|
+
|
|
136
|
+
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.
|
|
137
|
+
|
|
140
138
|
### `finder_param`
|
|
141
139
|
|
|
142
140
|
This method should return the parameter used to find the resource. Default: `:id`.
|
|
@@ -147,12 +145,38 @@ This method should return a boolean value to determine if the resource should be
|
|
|
147
145
|
|
|
148
146
|
### `friendly_finders?`
|
|
149
147
|
|
|
150
|
-
This method should return a boolean value to determine if the resource should be found using friendly finders.
|
|
148
|
+
This method should return a boolean value to determine if the resource should be found using friendly finders.
|
|
149
|
+
|
|
150
|
+
Default: `true` when `FriendlyId` is available **and** the model responds to `.friendly`, otherwise `false`.
|
|
151
|
+
|
|
152
|
+
### `parent_friendly_finders?`
|
|
153
|
+
|
|
154
|
+
When using nested routes (e.g. `/:parent_id/:id`), this method controls whether the **parent** should be found using FriendlyId.
|
|
155
|
+
|
|
156
|
+
Default: `friendly_finders?` (and additionally requires `FriendlyId` to be defined and the parent model to respond to `.friendly`).
|
|
151
157
|
|
|
152
158
|
### `skip_initialize_create?`
|
|
153
159
|
|
|
154
160
|
This method should return a boolean value to determine if the resource should be initialized on create. Default: `false`.
|
|
155
161
|
|
|
162
|
+
### `authorize_with_pundit?`
|
|
163
|
+
|
|
164
|
+
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.
|
|
165
|
+
|
|
166
|
+
For example:
|
|
167
|
+
|
|
168
|
+
```ruby
|
|
169
|
+
class ProductsController < ApplicationController
|
|
170
|
+
crudable
|
|
171
|
+
|
|
172
|
+
private
|
|
173
|
+
|
|
174
|
+
def authorize_with_pundit?
|
|
175
|
+
super && current_user.present? && feature_enabled?(:authorization)
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
```
|
|
179
|
+
|
|
156
180
|
### `(create|update)_params`
|
|
157
181
|
|
|
158
182
|
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.
|
data/Rakefile
CHANGED
data/lib/crudable/rails/base.rb
CHANGED
|
@@ -5,46 +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
|
-
after_action :authorize_resource, only: %i[new show edit] if defined?(Pundit)
|
|
13
17
|
|
|
14
18
|
decorates_assigned plural_resource_var_name.to_sym, resource_var_name.to_sym if defined?(Draper)
|
|
15
19
|
end
|
|
16
20
|
|
|
17
21
|
def index
|
|
22
|
+
authorize_class_action if authorize_with_pundit?
|
|
18
23
|
instance_variable_set("@#{plural_resource_var_name}", resource_scope)
|
|
19
24
|
paginate_resource
|
|
20
25
|
end
|
|
21
26
|
|
|
22
|
-
def show
|
|
27
|
+
def show
|
|
28
|
+
render_not_found if instance_variable_get("@#{resource_var_name}").blank?
|
|
29
|
+
authorize_resource if authorize_with_pundit?
|
|
30
|
+
end
|
|
23
31
|
|
|
24
32
|
def new
|
|
25
|
-
|
|
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?
|
|
26
39
|
end
|
|
27
40
|
|
|
28
|
-
def create
|
|
29
|
-
|
|
30
|
-
|
|
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?
|
|
31
53
|
before_authorize_create
|
|
32
54
|
authorize_resource
|
|
33
55
|
after_authorize_create
|
|
56
|
+
elsif authorize_with_pundit?
|
|
57
|
+
skip_authorization
|
|
34
58
|
end
|
|
35
|
-
if
|
|
59
|
+
if resource&.save
|
|
36
60
|
on_successful_create
|
|
37
61
|
on_successful_create_render
|
|
38
62
|
else
|
|
39
63
|
on_failed_create_setup
|
|
40
64
|
on_failed_create_render
|
|
41
65
|
end
|
|
66
|
+
rescue ActionController::ParameterMissing
|
|
67
|
+
head :bad_request
|
|
42
68
|
end
|
|
43
69
|
|
|
44
|
-
def edit
|
|
70
|
+
def edit
|
|
71
|
+
render_not_found if instance_variable_get("@#{resource_var_name}").blank?
|
|
72
|
+
authorize_resource if authorize_with_pundit?
|
|
73
|
+
end
|
|
45
74
|
|
|
46
75
|
def update
|
|
47
|
-
if
|
|
76
|
+
render_not_found if instance_variable_get("@#{resource_var_name}").blank?
|
|
77
|
+
if authorize_with_pundit?
|
|
48
78
|
before_authorize_update
|
|
49
79
|
authorize_resource
|
|
50
80
|
after_authorize_update
|
|
@@ -56,10 +86,12 @@ module Crudable
|
|
|
56
86
|
on_failed_update_setup
|
|
57
87
|
on_failed_update_render
|
|
58
88
|
end
|
|
89
|
+
rescue ActionController::ParameterMissing
|
|
90
|
+
head :bad_request
|
|
59
91
|
end
|
|
60
92
|
|
|
61
93
|
def destroy
|
|
62
|
-
authorize_resource(destroy_method) if
|
|
94
|
+
authorize_resource(destroy_method) if authorize_with_pundit?
|
|
63
95
|
if instance_variable_get("@#{resource_var_name}").send(destroy_method)
|
|
64
96
|
on_successful_destroy
|
|
65
97
|
on_successful_destroy_render
|
|
@@ -71,6 +103,10 @@ module Crudable
|
|
|
71
103
|
|
|
72
104
|
private
|
|
73
105
|
|
|
106
|
+
def authorize_with_pundit?
|
|
107
|
+
defined?(Pundit)
|
|
108
|
+
end
|
|
109
|
+
|
|
74
110
|
def destroy_method
|
|
75
111
|
return :destroy unless defined?(Discard)
|
|
76
112
|
return :destroy if params[:destroy]
|
|
@@ -84,11 +120,38 @@ module Crudable
|
|
|
84
120
|
|
|
85
121
|
def find_resource
|
|
86
122
|
resource = friendly_finders? ? resource_class.friendly : resource_class
|
|
87
|
-
instance =
|
|
123
|
+
instance = find_instance(resource)
|
|
88
124
|
|
|
89
125
|
return redirect_to (resource_namespace + [instance]), status: :moved_permanently if should_redirect?(instance)
|
|
90
126
|
|
|
91
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
|
|
92
155
|
end
|
|
93
156
|
|
|
94
157
|
def should_redirect?(instance)
|
|
@@ -110,7 +173,27 @@ module Crudable
|
|
|
110
173
|
end
|
|
111
174
|
|
|
112
175
|
def authorizable_scope
|
|
113
|
-
|
|
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
|
|
114
197
|
end
|
|
115
198
|
|
|
116
199
|
def paginate_resource?
|
|
@@ -139,6 +222,14 @@ module Crudable
|
|
|
139
222
|
end
|
|
140
223
|
|
|
141
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
|
|
142
233
|
resource_namespace + [plural_resource_var_name.to_sym]
|
|
143
234
|
end
|
|
144
235
|
|
|
@@ -215,16 +306,24 @@ module Crudable
|
|
|
215
306
|
def after_authorize_update; end
|
|
216
307
|
|
|
217
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
|
|
218
317
|
respond_to do |format|
|
|
219
318
|
format.turbo_stream { render_action(:new) }
|
|
220
|
-
format.html { render :new, status:
|
|
319
|
+
format.html { render :new, status: UNPROCESSABLE_STATUS }
|
|
221
320
|
end
|
|
222
321
|
end
|
|
223
322
|
|
|
224
323
|
def on_failed_update_render
|
|
225
324
|
respond_to do |format|
|
|
226
325
|
format.turbo_stream { render_action(:edit) }
|
|
227
|
-
format.html { render :edit, status:
|
|
326
|
+
format.html { render :edit, status: UNPROCESSABLE_STATUS }
|
|
228
327
|
end
|
|
229
328
|
end
|
|
230
329
|
|
|
@@ -245,14 +344,22 @@ module Crudable
|
|
|
245
344
|
end
|
|
246
345
|
|
|
247
346
|
def render_action(default_action_name)
|
|
248
|
-
logger.debug "Rendering relevant action for #{controller_path}/#{default_action_name}
|
|
249
|
-
|
|
347
|
+
logger.debug "Rendering relevant action for #{controller_path}/#{default_action_name} " \
|
|
348
|
+
"as #{request.format.symbol}"
|
|
349
|
+
if lookup_context.template_exists?("#{controller_path}/#{default_action_name}")
|
|
350
|
+
return render default_action_name
|
|
351
|
+
end
|
|
250
352
|
|
|
251
|
-
Crudable::Rails.deprecator.warn("Rendering fallback: #{action_name}, format: #{request.format.symbol}.
|
|
353
|
+
Crudable::Rails.deprecator.warn("Rendering fallback: #{action_name}, format: #{request.format.symbol}. " \
|
|
354
|
+
"Rename your template to #{default_action_name}")
|
|
252
355
|
|
|
253
356
|
logger.debug "Rendering fallback: #{action_name}"
|
|
254
357
|
render
|
|
255
358
|
end
|
|
359
|
+
|
|
360
|
+
def render_not_found
|
|
361
|
+
head :not_found
|
|
362
|
+
end
|
|
256
363
|
end
|
|
257
364
|
end
|
|
258
365
|
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,7 +7,7 @@ module Crudable
|
|
|
5
7
|
::ActionController::Base.include Crudable::Rails::Controller
|
|
6
8
|
end
|
|
7
9
|
|
|
8
|
-
initializer
|
|
10
|
+
initializer 'crudable-rails.deprecator' do |app|
|
|
9
11
|
app.deprecators[:crudable_rails] = Crudable::Rails.deprecator
|
|
10
12
|
end
|
|
11
13
|
end
|
|
@@ -7,20 +7,89 @@ module Crudable
|
|
|
7
7
|
extend ActiveSupport::Concern
|
|
8
8
|
|
|
9
9
|
included do
|
|
10
|
-
before_action :find_parent
|
|
10
|
+
before_action :find_parent
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def find_parent
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
return unless parent_present?
|
|
15
|
+
|
|
16
|
+
parent_scope = parent_class
|
|
17
|
+
parent_scope = parent_class.friendly if parent_friendly_finders?
|
|
18
|
+
instance_variable_set("@#{parent_var_name}", parent_scope.find(params[parent_id_param]))
|
|
19
|
+
self.class.send(:decorates_assigned, parent_var_name.to_sym) if defined?(Draper)
|
|
20
|
+
rescue ActiveRecord::RecordNotFound => e
|
|
21
|
+
# Only catch and render 404 if we're in a request context
|
|
22
|
+
# Check if we have a request object (indicates we're in a request context)
|
|
23
|
+
raise e unless respond_to?(:request, true) && !request.nil?
|
|
24
|
+
|
|
25
|
+
render_not_found
|
|
26
|
+
nil # Explicitly stop execution to prevent further action execution
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def parent_id_param
|
|
30
|
+
return nil unless use_parent_as_scope?
|
|
31
|
+
|
|
32
|
+
# Prefer route/path params (ordered by the route definition) over merged params
|
|
33
|
+
# (which may include query params).
|
|
34
|
+
# If multiple *_id params exist (multi-level nesting), default to the deepest/last one.
|
|
35
|
+
@parent_id_param ||= begin
|
|
36
|
+
keys = parent_id_param_keys
|
|
37
|
+
keys.map(&:to_s).grep(/(.+)_id$/).last
|
|
22
38
|
end
|
|
23
39
|
end
|
|
40
|
+
|
|
41
|
+
def parent_class
|
|
42
|
+
@parent_class ||= parent_var_name.classify.constantize
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def parent_var_name
|
|
46
|
+
@parent_var_name ||= parent_id_param.sub(/_id$/, '').underscore
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def parent_present?
|
|
50
|
+
!parent_id_param.nil?
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def parent_resource_association
|
|
54
|
+
return unless parent_present?
|
|
55
|
+
|
|
56
|
+
# Handle case where resource_class is a CollectionProxy (association proxy)
|
|
57
|
+
# Extract the actual class for comparison
|
|
58
|
+
actual_resource_class = if resource_class.is_a?(ActiveRecord::Associations::CollectionProxy)
|
|
59
|
+
resource_class.klass
|
|
60
|
+
else
|
|
61
|
+
resource_class
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
association = parent_class.reflect_on_all_associations.find { |assoc| assoc.klass == actual_resource_class }
|
|
65
|
+
association&.name
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# By default, if friendly finders are enabled for the resource, we will also attempt to use
|
|
69
|
+
# friendly finders for the parent (when available).
|
|
70
|
+
#
|
|
71
|
+
# Override this in your controller if you want to force parent lookup to use (or not use)
|
|
72
|
+
# FriendlyId, independently of the resource.
|
|
73
|
+
def parent_friendly_finders?
|
|
74
|
+
return false unless defined?(FriendlyId)
|
|
75
|
+
return false unless parent_class.respond_to?(:friendly)
|
|
76
|
+
|
|
77
|
+
friendly_finders?
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def use_parent_as_scope?
|
|
81
|
+
true
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def parent_id_param_keys
|
|
85
|
+
return request.path_parameters.keys if request_path_parameters_present?
|
|
86
|
+
|
|
87
|
+
params&.keys || []
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def request_path_parameters_present?
|
|
91
|
+
request.respond_to?(:path_parameters) && request.path_parameters.present?
|
|
92
|
+
end
|
|
24
93
|
end
|
|
25
94
|
end
|
|
26
95
|
end
|
|
@@ -31,11 +31,41 @@ module Crudable
|
|
|
31
31
|
def resource_namespace
|
|
32
32
|
namespaces = self.class.name.split('::')
|
|
33
33
|
namespaces.pop
|
|
34
|
-
namespaces.map { |n| n.
|
|
34
|
+
namespaces.map { |n| n.underscore.to_sym }
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
def authorize_resource(method = action_name)
|
|
38
|
-
|
|
38
|
+
return unless defined?(Pundit)
|
|
39
|
+
# Check if Pundit::Authorization is included (check class, ancestors, and respond_to)
|
|
40
|
+
return unless pundit_authorization_available?
|
|
41
|
+
|
|
42
|
+
authorize resource_namespace + [authorizable_resource], :"#{method}?"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def authorize_class_action(method = action_name)
|
|
46
|
+
return unless defined?(Pundit)
|
|
47
|
+
# Check if Pundit::Authorization is included (check class, ancestors, and respond_to)
|
|
48
|
+
return unless pundit_authorization_available?
|
|
49
|
+
|
|
50
|
+
authorize([*resource_namespace, resource_class], :"#{method}?")
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def pundit_authorization_available?
|
|
54
|
+
return false unless defined?(Pundit)
|
|
55
|
+
return false unless defined?(Pundit::Authorization)
|
|
56
|
+
# Check if included in this class
|
|
57
|
+
return true if self.class.included_modules.include?(Pundit::Authorization)
|
|
58
|
+
|
|
59
|
+
# Check if included in any ancestor (Class or Module)
|
|
60
|
+
# This handles cases where Pundit::Authorization is included in ApplicationController
|
|
61
|
+
ancestors_to_check = self.class.ancestors.select { |a| a.is_a?(Class) || a.is_a?(Module) }
|
|
62
|
+
return true if ancestors_to_check.any? { |ancestor| ancestor.included_modules.include?(Pundit::Authorization) }
|
|
63
|
+
# Fallback: check if authorize method is available (works in most cases)
|
|
64
|
+
# Use method_defined? for more reliable check than respond_to?
|
|
65
|
+
return true if self.class.method_defined?(:authorize) || self.class.private_method_defined?(:authorize)
|
|
66
|
+
|
|
67
|
+
# Last resort: respond_to check
|
|
68
|
+
respond_to?(:authorize, true)
|
|
39
69
|
end
|
|
40
70
|
|
|
41
71
|
def authorizable_resource
|
data/lib/crudable-rails.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'turbo-rails'
|
|
2
4
|
|
|
3
5
|
require 'crudable/rails/version'
|
|
@@ -10,7 +12,7 @@ require 'crudable/rails/nestable'
|
|
|
10
12
|
module Crudable
|
|
11
13
|
module Rails
|
|
12
14
|
def self.deprecator
|
|
13
|
-
@deprecator ||= ActiveSupport::Deprecation.new(
|
|
15
|
+
@deprecator ||= ActiveSupport::Deprecation.new('2.0', 'Crudable::Rails')
|
|
14
16
|
end
|
|
15
17
|
end
|
|
16
18
|
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Description:
|
|
2
|
+
Generates a Rails scaffold and replaces the generated controller with a Crudable controller.
|
|
3
|
+
|
|
4
|
+
Example:
|
|
5
|
+
bin/rails generate crudable:scaffold Thing
|
|
6
|
+
|
|
7
|
+
This will create:
|
|
8
|
+
It will generate a rails scaffold with a Crudable controller.
|
|
9
|
+
|
|
10
|
+
Notes:
|
|
11
|
+
Nested routing is automatically supported: if a parent `*_id` param is present and an association
|
|
12
|
+
exists between the parent and resource, collections and resources will be scoped through the parent.
|
|
13
|
+
Override `use_parent_as_scope?` in your controller to disable parent scoping.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Crudable
|
|
4
|
+
class ScaffoldGenerator < Rails::Generators::NamedBase
|
|
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'
|
|
10
|
+
|
|
11
|
+
hook_for :scaffold_controller, in: :rails
|
|
12
|
+
|
|
13
|
+
def crudable
|
|
14
|
+
template 'crudable_controller.rb',
|
|
15
|
+
File.join('app/controllers', controller_class_path, "#{controller_file_name}_controller.rb"), force: true
|
|
16
|
+
end
|
|
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?
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
<% module_namespacing do -%>
|
|
2
|
+
class <%= controller_class_name %>Controller < ApplicationController
|
|
3
|
+
crudable
|
|
4
|
+
|
|
5
|
+
private
|
|
6
|
+
|
|
7
|
+
# ---------------------------------------------------------------------------
|
|
8
|
+
# Optional overrides (self-documenting hooks)
|
|
9
|
+
#
|
|
10
|
+
# `crudable` mixes in `Crudable::Rails::Base` (which includes `Nestable`),
|
|
11
|
+
# which provides the REST actions and calls these hooks. Uncomment and tailor
|
|
12
|
+
# any of the following as needed.
|
|
13
|
+
# ---------------------------------------------------------------------------
|
|
14
|
+
#
|
|
15
|
+
# # If this resource is singular (e.g. SettingsController), return true.
|
|
16
|
+
# def singleton?
|
|
17
|
+
# false
|
|
18
|
+
# end
|
|
19
|
+
#
|
|
20
|
+
# # Which param key to use when finding a member resource (default :id).
|
|
21
|
+
# # Common examples: :slug, :uuid
|
|
22
|
+
# def finder_param
|
|
23
|
+
# :id
|
|
24
|
+
# end
|
|
25
|
+
#
|
|
26
|
+
# # Enable FriendlyId finders/redirects (default false).
|
|
27
|
+
# def friendly_finders?
|
|
28
|
+
# false
|
|
29
|
+
# end
|
|
30
|
+
#
|
|
31
|
+
# # Nested parent lookup: use FriendlyId for the parent (defaults to friendly_finders?).
|
|
32
|
+
# # This is only applied when FriendlyId is available and the parent model responds to `.friendly`.
|
|
33
|
+
# def parent_friendly_finders?
|
|
34
|
+
# friendly_finders?
|
|
35
|
+
# end
|
|
36
|
+
#
|
|
37
|
+
# # Enable pagination (requires Kaminari) (default true when Kaminari is defined).
|
|
38
|
+
# def paginate_resource?
|
|
39
|
+
# super
|
|
40
|
+
# end
|
|
41
|
+
#
|
|
42
|
+
# # Customize the scope used for index. This is the primary hook for filtering.
|
|
43
|
+
# # (HasScope is applied automatically if present.)
|
|
44
|
+
# def authorizable_scope
|
|
45
|
+
# super
|
|
46
|
+
# end
|
|
47
|
+
#
|
|
48
|
+
# # Full scope used for index (after HasScope, Pundit, etc).
|
|
49
|
+
# def resource_scope
|
|
50
|
+
# super
|
|
51
|
+
# end
|
|
52
|
+
#
|
|
53
|
+
# # Skip initializing a new instance in create (useful for custom create flows).
|
|
54
|
+
# def skip_initialize_create?
|
|
55
|
+
# false
|
|
56
|
+
# end
|
|
57
|
+
#
|
|
58
|
+
# # Discard/soft-delete support (requires Discard). When true, destroy will
|
|
59
|
+
# # choose discard vs destroy based on record state and params.
|
|
60
|
+
# def discard?
|
|
61
|
+
# false
|
|
62
|
+
# end
|
|
63
|
+
#
|
|
64
|
+
# # Control whether Pundit authorization should be performed.
|
|
65
|
+
# # Override this to customize authorization behavior (e.g., feature flags, user roles).
|
|
66
|
+
# # Default: returns true when Pundit is defined.
|
|
67
|
+
# def authorize_with_pundit?
|
|
68
|
+
# super
|
|
69
|
+
# end
|
|
70
|
+
#
|
|
71
|
+
# # Authorization lifecycle hooks (called inside create/update).
|
|
72
|
+
# def before_authorize_create; end
|
|
73
|
+
# def after_authorize_create; end
|
|
74
|
+
# def before_authorize_update; end
|
|
75
|
+
# def after_authorize_update; end
|
|
76
|
+
#
|
|
77
|
+
# # Post-success hooks (side-effects, instrumentation, etc).
|
|
78
|
+
# def on_successful_create; end
|
|
79
|
+
# def on_successful_update; end
|
|
80
|
+
#
|
|
81
|
+
# # Failure setup hooks (e.g., rebuild form collections).
|
|
82
|
+
# def on_failed_create_setup; end
|
|
83
|
+
# def on_failed_update_setup; end
|
|
84
|
+
#
|
|
85
|
+
# # Customize success redirects/flash messages.
|
|
86
|
+
# def after_create_redirect_path
|
|
87
|
+
# super
|
|
88
|
+
# end
|
|
89
|
+
#
|
|
90
|
+
# def after_create_notice
|
|
91
|
+
# super
|
|
92
|
+
# end
|
|
93
|
+
#
|
|
94
|
+
# def after_update_redirect_path
|
|
95
|
+
# super
|
|
96
|
+
# end
|
|
97
|
+
#
|
|
98
|
+
# def after_update_notice
|
|
99
|
+
# super
|
|
100
|
+
# end
|
|
101
|
+
#
|
|
102
|
+
# def after_destroy_redirect_path
|
|
103
|
+
# super
|
|
104
|
+
# end
|
|
105
|
+
#
|
|
106
|
+
# def after_failed_destroy_redirect_path
|
|
107
|
+
# super
|
|
108
|
+
# end
|
|
109
|
+
#
|
|
110
|
+
# def after_destroy_notice
|
|
111
|
+
# super
|
|
112
|
+
# end
|
|
113
|
+
#
|
|
114
|
+
# def after_failed_destroy_alert
|
|
115
|
+
# super
|
|
116
|
+
# end
|
|
117
|
+
#
|
|
118
|
+
# # Customize rendering for failed creates/updates (Turbo/HTML).
|
|
119
|
+
# def on_failed_create_render
|
|
120
|
+
# super
|
|
121
|
+
# end
|
|
122
|
+
#
|
|
123
|
+
# def on_failed_update_render
|
|
124
|
+
# super
|
|
125
|
+
# end
|
|
126
|
+
#
|
|
127
|
+
# # Customize rendering for destroy outcomes.
|
|
128
|
+
# def on_successful_destroy_render
|
|
129
|
+
# super
|
|
130
|
+
# end
|
|
131
|
+
#
|
|
132
|
+
# def on_failed_destroy_render
|
|
133
|
+
# super
|
|
134
|
+
# end
|
|
135
|
+
#
|
|
136
|
+
# # Nested resources: parent scoping is automatic when a `*_id` param is present.
|
|
137
|
+
# # Override `use_parent_as_scope?` to disable parent scoping.
|
|
138
|
+
# def find_parent
|
|
139
|
+
# super
|
|
140
|
+
# end
|
|
141
|
+
#
|
|
142
|
+
# def use_parent_as_scope?
|
|
143
|
+
# true
|
|
144
|
+
# end
|
|
145
|
+
#
|
|
146
|
+
# # Nested resources: customize which `*_id` param is treated as the parent id.
|
|
147
|
+
# # Useful for multi-level nesting or non-standard param names.
|
|
148
|
+
# def parent_id_param
|
|
149
|
+
# super
|
|
150
|
+
# end
|
|
151
|
+
#
|
|
152
|
+
# Strong params used by `create` (and by default `update` via `update_params`).
|
|
153
|
+
# Adjust the permitted attributes to match your model and nested params shape.
|
|
154
|
+
def create_params
|
|
155
|
+
<%- if attributes_names.empty? -%>
|
|
156
|
+
params.fetch(:<%= singular_table_name %>, {})
|
|
157
|
+
<%- else -%>
|
|
158
|
+
params.expect(<%= singular_table_name %>: [ <%= permitted_params %> ])
|
|
159
|
+
<%- end -%>
|
|
160
|
+
end
|
|
161
|
+
# By default, updates permit the same attributes as creates.
|
|
162
|
+
alias update_params create_params
|
|
163
|
+
end
|
|
164
|
+
<% end -%>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Description:
|
|
2
|
+
Extends the Rails scaffold controller generator with an option to generate a Crudable controller.
|
|
3
|
+
|
|
4
|
+
Example:
|
|
5
|
+
bin/rails generate scaffold Thing
|
|
6
|
+
|
|
7
|
+
This will create:
|
|
8
|
+
It will invoke the rails scaffold controller with an optional Crudable controller (use `--crudable`).
|
|
9
|
+
|
|
10
|
+
Notes:
|
|
11
|
+
Nested routing is automatically supported: if a parent `*_id` param is present and an association
|
|
12
|
+
exists between the parent and resource, collections and resources will be scoped through the parent.
|
|
13
|
+
Override `use_parent_as_scope?` in your controller to disable parent scoping.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class ScaffoldControllerGenerator < Rails::Generators::NamedBase
|
|
4
|
+
include Rails::Generators::ResourceHelpers
|
|
5
|
+
|
|
6
|
+
source_root File.expand_path('templates', __dir__)
|
|
7
|
+
|
|
8
|
+
class_exclusive do
|
|
9
|
+
class_option :crudable, type: :boolean, desc: 'Generate with crudable controller'
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
argument :attributes, type: :array, default: [], banner: 'field:type field:type'
|
|
13
|
+
|
|
14
|
+
hook_for :scaffold_controller, in: :rails
|
|
15
|
+
|
|
16
|
+
def crudable
|
|
17
|
+
return unless options.crudable?
|
|
18
|
+
|
|
19
|
+
template 'crudable_controller.rb',
|
|
20
|
+
File.join('app/controllers', controller_class_path, "#{controller_file_name}_controller.rb"), force: true
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def permitted_params
|
|
26
|
+
attachments, others = attributes_names.partition { |name| attachments?(name) }
|
|
27
|
+
params = others.map { |name| ":#{name}" }
|
|
28
|
+
params += attachments.map { |name| "#{name}: []" }
|
|
29
|
+
params.join(', ')
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def attachments?(name)
|
|
33
|
+
attribute = attributes.find { |attr| attr.name == name }
|
|
34
|
+
attribute&.attachments?
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
<% module_namespacing do -%>
|
|
2
|
+
class <%= controller_class_name %>Controller < ApplicationController
|
|
3
|
+
crudable
|
|
4
|
+
|
|
5
|
+
private
|
|
6
|
+
|
|
7
|
+
# ---------------------------------------------------------------------------
|
|
8
|
+
# Optional overrides (self-documenting hooks)
|
|
9
|
+
#
|
|
10
|
+
# `crudable` mixes in `Crudable::Rails::Base` (which includes `Nestable`),
|
|
11
|
+
# which provides the REST actions and calls these hooks. Uncomment and tailor
|
|
12
|
+
# any of the following as needed.
|
|
13
|
+
# ---------------------------------------------------------------------------
|
|
14
|
+
#
|
|
15
|
+
# # If this resource is singular (e.g. SettingsController), return true.
|
|
16
|
+
# def singleton?
|
|
17
|
+
# false
|
|
18
|
+
# end
|
|
19
|
+
#
|
|
20
|
+
# # Which param key to use when finding a member resource (default :id).
|
|
21
|
+
# # Common examples: :slug, :uuid
|
|
22
|
+
# def finder_param
|
|
23
|
+
# :id
|
|
24
|
+
# end
|
|
25
|
+
#
|
|
26
|
+
# # Enable FriendlyId finders/redirects (default false).
|
|
27
|
+
# def friendly_finders?
|
|
28
|
+
# false
|
|
29
|
+
# end
|
|
30
|
+
#
|
|
31
|
+
# # Nested parent lookup: use FriendlyId for the parent (defaults to friendly_finders?).
|
|
32
|
+
# # This is only applied when FriendlyId is available and the parent model responds to `.friendly`.
|
|
33
|
+
# def parent_friendly_finders?
|
|
34
|
+
# friendly_finders?
|
|
35
|
+
# end
|
|
36
|
+
#
|
|
37
|
+
# # Enable pagination (requires Kaminari) (default true when Kaminari is defined).
|
|
38
|
+
# def paginate_resource?
|
|
39
|
+
# super
|
|
40
|
+
# end
|
|
41
|
+
#
|
|
42
|
+
# # Customize the scope used for index. This is the primary hook for filtering.
|
|
43
|
+
# # (HasScope is applied automatically if present.)
|
|
44
|
+
# def authorizable_scope
|
|
45
|
+
# super
|
|
46
|
+
# end
|
|
47
|
+
#
|
|
48
|
+
# # Full scope used for index (after HasScope, Pundit, etc).
|
|
49
|
+
# def resource_scope
|
|
50
|
+
# super
|
|
51
|
+
# end
|
|
52
|
+
#
|
|
53
|
+
# # Skip initializing a new instance in create (useful for custom create flows).
|
|
54
|
+
# def skip_initialize_create?
|
|
55
|
+
# false
|
|
56
|
+
# end
|
|
57
|
+
#
|
|
58
|
+
# # Discard/soft-delete support (requires Discard). When true, destroy will
|
|
59
|
+
# # choose discard vs destroy based on record state and params.
|
|
60
|
+
# def discard?
|
|
61
|
+
# false
|
|
62
|
+
# end
|
|
63
|
+
#
|
|
64
|
+
# # Control whether Pundit authorization should be performed.
|
|
65
|
+
# # Override this to customize authorization behavior (e.g., feature flags, user roles).
|
|
66
|
+
# # Default: returns true when Pundit is defined.
|
|
67
|
+
# def authorize_with_pundit?
|
|
68
|
+
# super
|
|
69
|
+
# end
|
|
70
|
+
#
|
|
71
|
+
# # Authorization lifecycle hooks (called inside create/update).
|
|
72
|
+
# def before_authorize_create; end
|
|
73
|
+
# def after_authorize_create; end
|
|
74
|
+
# def before_authorize_update; end
|
|
75
|
+
# def after_authorize_update; end
|
|
76
|
+
#
|
|
77
|
+
# # Post-success hooks (side-effects, instrumentation, etc).
|
|
78
|
+
# def on_successful_create; end
|
|
79
|
+
# def on_successful_update; end
|
|
80
|
+
#
|
|
81
|
+
# # Failure setup hooks (e.g., rebuild form collections).
|
|
82
|
+
# def on_failed_create_setup; end
|
|
83
|
+
# def on_failed_update_setup; end
|
|
84
|
+
#
|
|
85
|
+
# # Customize success redirects/flash messages.
|
|
86
|
+
# def after_create_redirect_path
|
|
87
|
+
# super
|
|
88
|
+
# end
|
|
89
|
+
#
|
|
90
|
+
# def after_create_notice
|
|
91
|
+
# super
|
|
92
|
+
# end
|
|
93
|
+
#
|
|
94
|
+
# def after_update_redirect_path
|
|
95
|
+
# super
|
|
96
|
+
# end
|
|
97
|
+
#
|
|
98
|
+
# def after_update_notice
|
|
99
|
+
# super
|
|
100
|
+
# end
|
|
101
|
+
#
|
|
102
|
+
# def after_destroy_redirect_path
|
|
103
|
+
# super
|
|
104
|
+
# end
|
|
105
|
+
#
|
|
106
|
+
# def after_failed_destroy_redirect_path
|
|
107
|
+
# super
|
|
108
|
+
# end
|
|
109
|
+
#
|
|
110
|
+
# def after_destroy_notice
|
|
111
|
+
# super
|
|
112
|
+
# end
|
|
113
|
+
#
|
|
114
|
+
# def after_failed_destroy_alert
|
|
115
|
+
# super
|
|
116
|
+
# end
|
|
117
|
+
#
|
|
118
|
+
# # Customize rendering for failed creates/updates (Turbo/HTML).
|
|
119
|
+
# def on_failed_create_render
|
|
120
|
+
# super
|
|
121
|
+
# end
|
|
122
|
+
#
|
|
123
|
+
# def on_failed_update_render
|
|
124
|
+
# super
|
|
125
|
+
# end
|
|
126
|
+
#
|
|
127
|
+
# # Customize rendering for destroy outcomes.
|
|
128
|
+
# def on_successful_destroy_render
|
|
129
|
+
# super
|
|
130
|
+
# end
|
|
131
|
+
#
|
|
132
|
+
# def on_failed_destroy_render
|
|
133
|
+
# super
|
|
134
|
+
# end
|
|
135
|
+
#
|
|
136
|
+
# # Nested resources: parent scoping is automatic when a `*_id` param is present.
|
|
137
|
+
# # Override `use_parent_as_scope?` to disable parent scoping.
|
|
138
|
+
# def find_parent
|
|
139
|
+
# super
|
|
140
|
+
# end
|
|
141
|
+
#
|
|
142
|
+
# def use_parent_as_scope?
|
|
143
|
+
# true
|
|
144
|
+
# end
|
|
145
|
+
#
|
|
146
|
+
# # Nested resources: customize which `*_id` param is treated as the parent id.
|
|
147
|
+
# # Useful for multi-level nesting or non-standard param names.
|
|
148
|
+
# def parent_id_param
|
|
149
|
+
# super
|
|
150
|
+
# end
|
|
151
|
+
#
|
|
152
|
+
# Strong params used by `create` (and by default `update` via `update_params`).
|
|
153
|
+
# Adjust the permitted attributes to match your model and nested params shape.
|
|
154
|
+
def create_params
|
|
155
|
+
<%- if attributes_names.empty? -%>
|
|
156
|
+
params.fetch(:<%= singular_table_name %>, {})
|
|
157
|
+
<%- else -%>
|
|
158
|
+
params.expect(<%= singular_table_name %>: [ <%= permitted_params %> ])
|
|
159
|
+
<%- end -%>
|
|
160
|
+
end
|
|
161
|
+
# By default, updates permit the same attributes as creates.
|
|
162
|
+
alias update_params create_params
|
|
163
|
+
end
|
|
164
|
+
<% end -%>
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: crudable-rails
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tomislav Simnett
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: rails
|
|
@@ -16,7 +15,7 @@ dependencies:
|
|
|
16
15
|
requirements:
|
|
17
16
|
- - ">="
|
|
18
17
|
- !ruby/object:Gem::Version
|
|
19
|
-
version:
|
|
18
|
+
version: 7.1.0
|
|
20
19
|
- - "<"
|
|
21
20
|
- !ruby/object:Gem::Version
|
|
22
21
|
version: 9.0.0
|
|
@@ -26,7 +25,7 @@ dependencies:
|
|
|
26
25
|
requirements:
|
|
27
26
|
- - ">="
|
|
28
27
|
- !ruby/object:Gem::Version
|
|
29
|
-
version:
|
|
28
|
+
version: 7.1.0
|
|
30
29
|
- - "<"
|
|
31
30
|
- !ruby/object:Gem::Version
|
|
32
31
|
version: 9.0.0
|
|
@@ -45,45 +44,45 @@ dependencies:
|
|
|
45
44
|
- !ruby/object:Gem::Version
|
|
46
45
|
version: 2.0.0
|
|
47
46
|
- !ruby/object:Gem::Dependency
|
|
48
|
-
name:
|
|
47
|
+
name: mocha
|
|
49
48
|
requirement: !ruby/object:Gem::Requirement
|
|
50
49
|
requirements:
|
|
51
50
|
- - ">="
|
|
52
51
|
- !ruby/object:Gem::Version
|
|
53
|
-
version: '
|
|
52
|
+
version: '2.6'
|
|
54
53
|
- - "<"
|
|
55
54
|
- !ruby/object:Gem::Version
|
|
56
|
-
version:
|
|
55
|
+
version: 3.0.0
|
|
57
56
|
type: :development
|
|
58
57
|
prerelease: false
|
|
59
58
|
version_requirements: !ruby/object:Gem::Requirement
|
|
60
59
|
requirements:
|
|
61
60
|
- - ">="
|
|
62
61
|
- !ruby/object:Gem::Version
|
|
63
|
-
version: '
|
|
62
|
+
version: '2.6'
|
|
64
63
|
- - "<"
|
|
65
64
|
- !ruby/object:Gem::Version
|
|
66
|
-
version:
|
|
65
|
+
version: 3.0.0
|
|
67
66
|
- !ruby/object:Gem::Dependency
|
|
68
|
-
name:
|
|
67
|
+
name: rubocop
|
|
69
68
|
requirement: !ruby/object:Gem::Requirement
|
|
70
69
|
requirements:
|
|
71
70
|
- - ">="
|
|
72
71
|
- !ruby/object:Gem::Version
|
|
73
|
-
version: '
|
|
72
|
+
version: '1.50'
|
|
74
73
|
- - "<"
|
|
75
74
|
- !ruby/object:Gem::Version
|
|
76
|
-
version:
|
|
75
|
+
version: '2.0'
|
|
77
76
|
type: :development
|
|
78
77
|
prerelease: false
|
|
79
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
80
79
|
requirements:
|
|
81
80
|
- - ">="
|
|
82
81
|
- !ruby/object:Gem::Version
|
|
83
|
-
version: '
|
|
82
|
+
version: '1.50'
|
|
84
83
|
- - "<"
|
|
85
84
|
- !ruby/object:Gem::Version
|
|
86
|
-
version:
|
|
85
|
+
version: '2.0'
|
|
87
86
|
description: Crudable Rails provides everything needed to quickly build fully functional
|
|
88
87
|
CRUD-based controllers in a Rails application. It streamlines resource management,
|
|
89
88
|
reduces boilerplate, and enforces best practices for handling requests, responses,
|
|
@@ -106,12 +105,18 @@ files:
|
|
|
106
105
|
- lib/crudable/rails/nestable.rb
|
|
107
106
|
- lib/crudable/rails/resourceable.rb
|
|
108
107
|
- lib/crudable/rails/version.rb
|
|
108
|
+
- lib/generators/crudable/scaffold/USAGE
|
|
109
|
+
- lib/generators/crudable/scaffold/scaffold_generator.rb
|
|
110
|
+
- lib/generators/crudable/scaffold/templates/crudable_controller.rb.tt
|
|
111
|
+
- lib/generators/scaffold_controller/USAGE
|
|
112
|
+
- lib/generators/scaffold_controller/scaffold_controller_generator.rb
|
|
113
|
+
- lib/generators/scaffold_controller/templates/crudable_controller.rb.tt
|
|
109
114
|
- lib/tasks/crudable_tasks.rake
|
|
110
115
|
homepage: https://gitlab.com/initforthe/crudable-rails
|
|
111
116
|
licenses:
|
|
112
117
|
- MIT
|
|
113
|
-
metadata:
|
|
114
|
-
|
|
118
|
+
metadata:
|
|
119
|
+
rubygems_mfa_required: 'true'
|
|
115
120
|
rdoc_options: []
|
|
116
121
|
require_paths:
|
|
117
122
|
- lib
|
|
@@ -126,8 +131,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
126
131
|
- !ruby/object:Gem::Version
|
|
127
132
|
version: '0'
|
|
128
133
|
requirements: []
|
|
129
|
-
rubygems_version:
|
|
130
|
-
signing_key:
|
|
134
|
+
rubygems_version: 4.0.12
|
|
131
135
|
specification_version: 4
|
|
132
136
|
summary: CRUD operations for Rails controllers
|
|
133
137
|
test_files: []
|