garden_variety 1.2 → 2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|