garden_variety 1.2 → 2.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 +128 -52
- data/lib/garden_variety/actions.rb +16 -2
- data/lib/garden_variety/controller.rb +89 -0
- data/lib/garden_variety/version.rb +1 -1
- data/lib/generators/garden/install/install_generator.rb +18 -0
- data/lib/generators/garden/install/templates/locales/garden_variety.en.yml +10 -0
- data/lib/generators/garden/scaffold/scaffold_generator.rb +6 -0
- metadata +3 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b80f333fab73447d743d99ef4cd170a997011a8e
|
4
|
+
data.tar.gz: ab23ee38fd1a658f8fa7a82eeac8708110346bb4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1a36d05543168c2739e1b2677aa4b870c534ca4a5fc340a80ae80f18e920b238c59017179cd16e5824f2bce62ac36db3ca73a4c80f98a5e8f61381de597ef336
|
7
|
+
data.tar.gz: a93377a1e7c252f6ad547febe70bdaedc83a62383819e04766bda20b604f5db055571d17fa7d56b5a4680eccb0d124bf54d5171787a5a1858cdb472b80cbc58f
|
data/README.md
CHANGED
@@ -48,8 +48,10 @@ class PostsController < ApplicationController
|
|
48
48
|
def create
|
49
49
|
self.resource = vest(new_resource)
|
50
50
|
if resource.save
|
51
|
+
flash[:success] = flash_message(:success)
|
51
52
|
redirect_to resource
|
52
53
|
else
|
54
|
+
flash.now[:error] = flash_message(:error)
|
53
55
|
render :new
|
54
56
|
end
|
55
57
|
end
|
@@ -62,8 +64,10 @@ class PostsController < ApplicationController
|
|
62
64
|
def update
|
63
65
|
self.resource = vest(find_resource)
|
64
66
|
if resource.save
|
67
|
+
flash[:success] = flash_message(:success)
|
65
68
|
redirect_to resource
|
66
69
|
else
|
70
|
+
flash.now[:error] = flash_message(:error)
|
67
71
|
render :edit
|
68
72
|
end
|
69
73
|
end
|
@@ -71,8 +75,13 @@ class PostsController < ApplicationController
|
|
71
75
|
def destroy
|
72
76
|
self.resource = find_resource
|
73
77
|
authorize(resource)
|
74
|
-
resource.destroy
|
75
|
-
|
78
|
+
if resource.destroy
|
79
|
+
flash[:success] = flash_message(:success)
|
80
|
+
redirect_to action: :index
|
81
|
+
else
|
82
|
+
flash.now[:error] = flash_message(:error)
|
83
|
+
render :show
|
84
|
+
end
|
76
85
|
end
|
77
86
|
|
78
87
|
private
|
@@ -115,6 +124,22 @@ class PostsController < ApplicationController
|
|
115
124
|
model
|
116
125
|
end
|
117
126
|
|
127
|
+
def flash_options
|
128
|
+
{ resource_name: "post", resource_capitalized: "Post" }
|
129
|
+
end
|
130
|
+
|
131
|
+
def flash_message(status)
|
132
|
+
keys = [
|
133
|
+
:"posts.#{action_name}.#{status}",
|
134
|
+
:"posts.#{action_name}.#{status}_html",
|
135
|
+
:"#{action_name}.#{status}",
|
136
|
+
:"#{action_name}.#{status}_html",
|
137
|
+
:"#{status}",
|
138
|
+
:"#{status}_html",
|
139
|
+
]
|
140
|
+
helpers.translate(keys.first, default: keys.drop(1), **flash_options)
|
141
|
+
end
|
142
|
+
|
118
143
|
end
|
119
144
|
```
|
120
145
|
|
@@ -182,17 +207,60 @@ generator in a few small ways:
|
|
182
207
|
* `rails generate pundit:policy` is invoked for the specified model.
|
183
208
|
|
184
209
|
|
210
|
+
## Flash messages
|
211
|
+
|
212
|
+
Flash messages are defined using I18n. The *garden_variety* installer
|
213
|
+
(`rails generate garden:install`) will create a
|
214
|
+
"config/locales/garden_variety.en.yml" file containing default "success"
|
215
|
+
and "error" messages. You can edit this file to customize those
|
216
|
+
messages, or add your own translation files to support other languages.
|
217
|
+
|
218
|
+
As seen in the `PostsController#flash_message` method in the example
|
219
|
+
above, a prioritized list of keys are tried when retrieving a flash
|
220
|
+
message. Keys specific to the controller are tried first, followed by
|
221
|
+
keys specific to the action, and then finally generic status keys. For
|
222
|
+
each level of specificity, `*_html` key variants are supported, which
|
223
|
+
allow raw HTML to be included in flash messages and not be escaped when
|
224
|
+
rendered. (See the [Safe HTML Translations] section of the Rails
|
225
|
+
Internationalization guide for more information.)
|
226
|
+
|
227
|
+
Interpolation in flash messages is also supported (as described by
|
228
|
+
[Passing Variables to Translations]), with interpolation values provided
|
229
|
+
by the `flash_options` method. By default, `flash_options` provides
|
230
|
+
`resource_name` and `resource_capitalized` values, but you can override
|
231
|
+
it to provide your own values.
|
232
|
+
|
233
|
+
[Safe HTML Translations]: http://guides.rubyonrails.org/i18n.html#using-safe-html-translations
|
234
|
+
[Passing Variables to Translations]: http://guides.rubyonrails.org/i18n.html#passing-variables-to-translations
|
235
|
+
|
236
|
+
|
185
237
|
## Beyond garden variety behavior
|
186
238
|
|
187
239
|
*garden_variety* is designed to reduce the amount of custom code
|
188
240
|
written, including in situations where custom code is unavoidable.
|
189
241
|
|
190
242
|
|
243
|
+
### Integrating with pagination
|
244
|
+
|
245
|
+
You can integrate your your favorite pagination gem (*may I suggest
|
246
|
+
[foliate](https://rubygems.org/gems/foliate)?*) by overriding the
|
247
|
+
`list_resources` method:
|
248
|
+
|
249
|
+
```ruby
|
250
|
+
class PostsController < ApplicationController
|
251
|
+
garden_variety
|
252
|
+
|
253
|
+
def list_resources
|
254
|
+
paginate(super)
|
255
|
+
end
|
256
|
+
end
|
257
|
+
```
|
258
|
+
|
259
|
+
|
191
260
|
### Integrating with search
|
192
261
|
|
193
|
-
|
194
|
-
`
|
195
|
-
`list_resources` method instead:
|
262
|
+
You can also integrate search functionality by overriding the
|
263
|
+
`list_resources` method:
|
196
264
|
|
197
265
|
```ruby
|
198
266
|
class PostsController < ApplicationController
|
@@ -205,22 +273,55 @@ end
|
|
205
273
|
```
|
206
274
|
|
207
275
|
|
208
|
-
### Integrating with
|
276
|
+
### Integrating with SJR
|
209
277
|
|
210
|
-
|
211
|
-
|
212
|
-
|
278
|
+
Server-generated JavaScript Response (SJR) controller actions are
|
279
|
+
generally the same as conventional controller actions, with one
|
280
|
+
difference: non-GET SJR actions render instead of redirect on success.
|
281
|
+
*garden_variety* provides a concise syntax for overriding only
|
282
|
+
on-success behavior of non-GET actions:
|
213
283
|
|
214
284
|
```ruby
|
215
285
|
class PostsController < ApplicationController
|
216
286
|
garden_variety
|
217
287
|
|
218
|
-
def
|
219
|
-
|
288
|
+
def create
|
289
|
+
super{ render plain: "text" } # renders text on success instead of redirect
|
290
|
+
end
|
291
|
+
end
|
292
|
+
```
|
293
|
+
|
294
|
+
Thus, combining this syntax with Rails' default rendering convention:
|
295
|
+
|
296
|
+
```ruby
|
297
|
+
class PostsController < ApplicationController
|
298
|
+
garden_variety
|
299
|
+
|
300
|
+
def create
|
301
|
+
respond_to do |format|
|
302
|
+
format.js{ super{} } # renders "app/views/posts/create.js.erb" on success
|
303
|
+
end
|
220
304
|
end
|
305
|
+
|
306
|
+
def update
|
307
|
+
respond_to do |format|
|
308
|
+
format.js{ super{} } # renders "app/views/posts/update.js.erb" on success
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
def destroy
|
313
|
+
respond_to do |format|
|
314
|
+
format.js{ super{} } # renders "app/views/posts/destroy.js.erb" on success
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
221
318
|
end
|
222
319
|
```
|
223
320
|
|
321
|
+
**Sidenote:** *garden_variety* automatically manages the life of flash
|
322
|
+
messages. If a redirect is replaced with a render, the flash message
|
323
|
+
will be set such that it does not affect the next request.
|
324
|
+
|
224
325
|
|
225
326
|
### Integrating with authentication
|
226
327
|
|
@@ -287,58 +388,32 @@ end
|
|
287
388
|
|
288
389
|
|
289
390
|
class RegistrationFormsController < ApplicationController
|
290
|
-
garden_variety :new
|
391
|
+
garden_variety :new, :create # only generate #new and #create actions
|
291
392
|
|
292
393
|
def create
|
293
|
-
|
294
|
-
if resource.save
|
295
|
-
redirect_to root_path # redirect to front page instead of show
|
296
|
-
else
|
297
|
-
render :new
|
298
|
-
end
|
394
|
+
super{ redirect_to root_path } # redirect to home page on success
|
299
395
|
end
|
300
396
|
end
|
301
397
|
```
|
302
398
|
|
303
|
-
|
304
|
-
macro. The `create`
|
305
|
-
to `root_path
|
306
|
-
|
399
|
+
In this example, only the `new` and `create` actions are generated by
|
400
|
+
the `garden_variety` macro. The on-success behavior of `create` is
|
401
|
+
overridden to redirect to `root_path`, using the concise syntax
|
402
|
+
discussed in the [Integrating with SJR](#integrating-with-sjr) example.
|
403
|
+
The *garden_variety* controller helper methods all work as expected
|
307
404
|
because `RegistrationForm` responds to `assign_attributes` and `save`,
|
308
405
|
and has a default (nullary) constructor.
|
309
406
|
|
310
|
-
This pattern of overriding a controller action merely to respond
|
311
|
-
differently upon success is common enough that *garden_variety* provides
|
312
|
-
a concise syntax for it:
|
313
|
-
|
314
|
-
```ruby
|
315
|
-
class RegistrationFormsController < ApplicationController
|
316
|
-
garden_variety :new, :create
|
317
|
-
|
318
|
-
def create
|
319
|
-
super{ redirect_to root_path }
|
320
|
-
end
|
321
|
-
end
|
322
|
-
```
|
323
|
-
|
324
|
-
In the above example, the `garden_variety` macro generates a
|
325
|
-
conventional `create` action, which is then invoked via `super` in the
|
326
|
-
`create` override. Here, when a block is passed to `super`, it is
|
327
|
-
treated as an on-success callback which replaces the default redirect.
|
328
|
-
This callback behavior is also available for the `update` and `destroy`
|
329
|
-
actions.
|
330
|
-
|
331
407
|
|
332
408
|
### Non-REST actions
|
333
409
|
|
334
410
|
You may also define any non-REST controller actions you wish (i.e.
|
335
411
|
actions other than: `index`, `show`, `new`, `create`, `edit`, `update`,
|
336
|
-
and `destroy`). The helper methods *garden_variety* provides
|
337
|
-
useful when doing so.
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
controller. For example, instead of the following `published` action...
|
412
|
+
and `destroy`). The controller helper methods *garden_variety* provides
|
413
|
+
may be useful when doing so. However, before implementing a non-REST
|
414
|
+
controller action, consider if the behavior might be better implemented
|
415
|
+
as a REST action in a new controller. For example, instead of the
|
416
|
+
following `published` action...
|
342
417
|
|
343
418
|
```ruby
|
344
419
|
class PostsController < ApplicationController
|
@@ -388,13 +463,14 @@ Then execute:
|
|
388
463
|
$ bundle install
|
389
464
|
```
|
390
465
|
|
391
|
-
And finally,
|
392
|
-
Pundit installation generator:
|
466
|
+
And finally, run the *garden_variety* install generator:
|
393
467
|
|
394
468
|
```bash
|
395
|
-
$ rails generate
|
469
|
+
$ rails generate garden:install
|
396
470
|
```
|
397
471
|
|
472
|
+
This will also run the Pundit install generator, if necessary.
|
473
|
+
|
398
474
|
|
399
475
|
## Contributing
|
400
476
|
|
@@ -1,5 +1,7 @@
|
|
1
1
|
module GardenVariety
|
2
2
|
|
3
|
+
REDIRECT_CODES = [301, 302, 303, 307, 308]
|
4
|
+
|
3
5
|
module IndexAction
|
4
6
|
# Garden variety controller +index+ action.
|
5
7
|
# @return [void]
|
@@ -40,8 +42,11 @@ module GardenVariety
|
|
40
42
|
def create
|
41
43
|
self.resource = vest(new_resource)
|
42
44
|
if resource.save
|
45
|
+
flash[:success] = flash_message(:success)
|
43
46
|
block_given? ? yield : redirect_to(resource)
|
47
|
+
flash.discard(:success) if REDIRECT_CODES.exclude?(response.status)
|
44
48
|
else
|
49
|
+
flash.now[:error] = flash_message(:error)
|
45
50
|
render :new
|
46
51
|
end
|
47
52
|
end
|
@@ -65,8 +70,11 @@ module GardenVariety
|
|
65
70
|
def update
|
66
71
|
self.resource = vest(find_resource)
|
67
72
|
if resource.save
|
73
|
+
flash[:success] = flash_message(:success)
|
68
74
|
block_given? ? yield : redirect_to(resource)
|
75
|
+
flash.discard(:success) if REDIRECT_CODES.exclude?(response.status)
|
69
76
|
else
|
77
|
+
flash.now[:error] = flash_message(:error)
|
70
78
|
render :edit
|
71
79
|
end
|
72
80
|
end
|
@@ -81,8 +89,14 @@ module GardenVariety
|
|
81
89
|
def destroy
|
82
90
|
self.resource = find_resource
|
83
91
|
authorize(resource)
|
84
|
-
resource.destroy
|
85
|
-
|
92
|
+
if resource.destroy
|
93
|
+
flash[:success] = flash_message(:success)
|
94
|
+
block_given? ? yield : redirect_to(action: :index)
|
95
|
+
flash.discard(:success) if REDIRECT_CODES.exclude?(response.status)
|
96
|
+
else
|
97
|
+
flash.now[:error] = flash_message(:error)
|
98
|
+
render :show
|
99
|
+
end
|
86
100
|
end
|
87
101
|
end
|
88
102
|
|
@@ -224,5 +224,94 @@ module GardenVariety
|
|
224
224
|
model.assign_attributes(permitted_attributes(model))
|
225
225
|
model
|
226
226
|
end
|
227
|
+
|
228
|
+
# @!visibility public
|
229
|
+
# Returns Hash of values for interpolation in flash messages via
|
230
|
+
# I18n. By default, returns +resource_name+ and
|
231
|
+
# +resource_capitalized+ values appropriate to the controller.
|
232
|
+
# Override this method to provide your own values. Be aware that
|
233
|
+
# certain option names, such as +default+ and +scope+, are reserved
|
234
|
+
# by the I18n gem, and can not be used for interpolation. See the
|
235
|
+
# {https://www.rubydoc.info/gems/i18n I18n documentation} for more
|
236
|
+
# information.
|
237
|
+
#
|
238
|
+
# @return [Hash]
|
239
|
+
def flash_options
|
240
|
+
{ resource_name: resource_class.model_name.human.downcase,
|
241
|
+
resource_capitalized: resource_class.model_name.human }
|
242
|
+
end
|
243
|
+
|
244
|
+
# @!visibility public
|
245
|
+
# Returns a flash message appropriate to the controller, the current
|
246
|
+
# action, and a given status. The flash message is looked up via
|
247
|
+
# I18n using a prioritized list of possible keys. The key priority
|
248
|
+
# is as follows:
|
249
|
+
#
|
250
|
+
# * +{controller_name}.{action_name}.{status}+
|
251
|
+
# * +{controller_name}.{action_name}.{status}_html+
|
252
|
+
# * +{action_name}.{status}+
|
253
|
+
# * +{action_name}.{status}_html+
|
254
|
+
# * +{status}+
|
255
|
+
# * +{status}_html+
|
256
|
+
#
|
257
|
+
# If the controller is namespaced, the namespace will prefix
|
258
|
+
# (dot-separated) the +{controller_name}+ portion of the key.
|
259
|
+
#
|
260
|
+
# I18n string interpolation can be used in flash messages, with
|
261
|
+
# interpolated values provided by the {flash_options} method.
|
262
|
+
#
|
263
|
+
# @example Key priority
|
264
|
+
# ### config/locales/garden_variety.en.yml
|
265
|
+
# # en:
|
266
|
+
# # success: "Success!"
|
267
|
+
# # create:
|
268
|
+
# # success: "%{resource_capitalized} created."
|
269
|
+
# # delete:
|
270
|
+
# # success: "%{resource_capitalized} deleted."
|
271
|
+
# # posts:
|
272
|
+
# # create:
|
273
|
+
# # success: "Congratulations on your new post!"
|
274
|
+
#
|
275
|
+
# # via PostsController#create
|
276
|
+
# flash_message(:success) # == "Congratulations on your new post!"
|
277
|
+
#
|
278
|
+
# # via PostsController#update
|
279
|
+
# flash_message(:success) # == "Success!"
|
280
|
+
#
|
281
|
+
# # via PostsController#delete
|
282
|
+
# flash_message(:success) # == "Post deleted."
|
283
|
+
#
|
284
|
+
# @example Namespaced controller
|
285
|
+
# ### config/locales/garden_variety.en.yml
|
286
|
+
# # en:
|
287
|
+
# # create:
|
288
|
+
# # success: "Created new %{resource_name}."
|
289
|
+
# # update:
|
290
|
+
# # success: "Updated %{resource_name}."
|
291
|
+
# # messages:
|
292
|
+
# # drafts:
|
293
|
+
# # update:
|
294
|
+
# # success: "Draft saved."
|
295
|
+
#
|
296
|
+
# # via Messages::DraftsController#create
|
297
|
+
# flash_message(:success) # == "Created new draft."
|
298
|
+
#
|
299
|
+
# # via Messages::DraftsController#update
|
300
|
+
# flash_message(:success) # == "Draft saved."
|
301
|
+
#
|
302
|
+
# @param status [Symbol, String]
|
303
|
+
# @return [String]
|
304
|
+
def flash_message(status)
|
305
|
+
controller_key = controller_path.tr("/", I18n.default_separator)
|
306
|
+
keys = [
|
307
|
+
:"#{controller_key}.#{action_name}.#{status}",
|
308
|
+
:"#{controller_key}.#{action_name}.#{status}_html",
|
309
|
+
:"#{action_name}.#{status}",
|
310
|
+
:"#{action_name}.#{status}_html",
|
311
|
+
:"#{status}",
|
312
|
+
:"#{status}_html",
|
313
|
+
]
|
314
|
+
helpers.translate(keys.shift, default: keys, **flash_options)
|
315
|
+
end
|
227
316
|
end
|
228
317
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "rails/generators/base"
|
2
|
+
|
3
|
+
# @!visibility private
|
4
|
+
module Garden
|
5
|
+
module Generators
|
6
|
+
class InstallGenerator < Rails::Generators::Base
|
7
|
+
source_root File.join(__dir__, "templates")
|
8
|
+
|
9
|
+
def copy_locales
|
10
|
+
directory "locales", "config/locales"
|
11
|
+
end
|
12
|
+
|
13
|
+
def install_pundit
|
14
|
+
generate("pundit:install", "--skip")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
en:
|
2
|
+
create:
|
3
|
+
success: '%{resource_capitalized} was successfully created.'
|
4
|
+
error: 'Could not create %{resource_name}.'
|
5
|
+
update:
|
6
|
+
success: '%{resource_capitalized} was successfully updated.'
|
7
|
+
error: 'Could not update %{resource_name}.'
|
8
|
+
destroy:
|
9
|
+
success: '%{resource_capitalized} was successfully destroyed.'
|
10
|
+
error: 'Could not destroy %{resource_name}.'
|
@@ -4,6 +4,8 @@ require "rails/generators/base"
|
|
4
4
|
module Garden
|
5
5
|
module Generators
|
6
6
|
class ScaffoldGenerator < Rails::Generators::Base
|
7
|
+
source_root File.join(__dir__, "templates")
|
8
|
+
|
7
9
|
argument :resource, type: :string
|
8
10
|
|
9
11
|
# NOTE: an appropriate default value for template_engine (e.g.
|
@@ -20,6 +22,10 @@ module Garden
|
|
20
22
|
super
|
21
23
|
end
|
22
24
|
|
25
|
+
def ensure_locales
|
26
|
+
directory "../../install/templates/locales", "config/locales", skip: true
|
27
|
+
end
|
28
|
+
|
23
29
|
def generate_scaffolding
|
24
30
|
generate("resource", *@argv)
|
25
31
|
generate("#{options[:template_engine]}:scaffold", *@argv)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: garden_variety
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '
|
4
|
+
version: '2.0'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonathan Hefner
|
@@ -82,6 +82,8 @@ files:
|
|
82
82
|
- lib/garden_variety/current_user_stub.rb
|
83
83
|
- lib/garden_variety/railtie.rb
|
84
84
|
- lib/garden_variety/version.rb
|
85
|
+
- lib/generators/garden/install/install_generator.rb
|
86
|
+
- lib/generators/garden/install/templates/locales/garden_variety.en.yml
|
85
87
|
- lib/generators/garden/scaffold/scaffold_generator.rb
|
86
88
|
homepage: https://github.com/jonathanhefner/garden_variety
|
87
89
|
licenses:
|