garden_variety 1.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9e0504f9a8b485b41628697e9b5b3061e697874d
4
+ data.tar.gz: 69d7067b8054ce75955a12cf47420901f4badf0b
5
+ SHA512:
6
+ metadata.gz: 3cb5e7ee8a146481586d7aa7efabdd48efa03e34617c3f9cd6e46bab3a8730210cc12d3ad9c1ec5d9d17daa675b17b8f08ae6481ac8545a8cc27f7a830b9fe40
7
+ data.tar.gz: 1e02647816ee226bf0d46dc7933e74aff5f28a465abbf75d4722d2e69c287581b7b2da56cfbc7fd7fe629705cd19d8beb6eb800b8a7d7e0ff786b276287d822e
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2017
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,382 @@
1
+ # garden_variety
2
+
3
+ Delightfully boring Rails controllers. One of the superb advantages of
4
+ Ruby on Rails is convention over configuration. Opinionated default
5
+ behavior can decrease development time, and increase application
6
+ robustness (less custom code == less that can go wrong). In service of
7
+ this principle, *garden_variety* provides reasonable default controller
8
+ actions, with care to allow easy override.
9
+
10
+ *garden_variety* also uses the excellent
11
+ [Pundit](https://rubygems.org/gems/pundit) gem to isolate authorization
12
+ concerns. If you're unfamiliar with Pundit, see its documentation for
13
+ an explanation of policy objects and how they help controller actions
14
+ stay DRY and boring.
15
+
16
+ As an example, this controller using `garden_variety`...
17
+
18
+ ```ruby
19
+ class PostsController < ApplicationController
20
+ garden_variety
21
+ end
22
+ ```
23
+
24
+ ...expands to the following conventional implementation:
25
+
26
+ ```ruby
27
+ class PostsController < ApplicationController
28
+
29
+ def index
30
+ authorize(resource_class)
31
+ self.resources = policy_scope(list_resources)
32
+ end
33
+
34
+ def show
35
+ self.resource = find_resource
36
+ authorize(resource)
37
+ end
38
+
39
+ def new
40
+ self.resource = new_resource
41
+ authorize(resource)
42
+ end
43
+
44
+ def create
45
+ self.resource = vest(new_resource)
46
+ if resource.save
47
+ redirect_to resource
48
+ else
49
+ render :new
50
+ end
51
+ end
52
+
53
+ def edit
54
+ self.resource = find_resource
55
+ authorize(resource)
56
+ end
57
+
58
+ def update
59
+ self.resource = vest(find_resource)
60
+ if resource.save
61
+ redirect_to resource
62
+ else
63
+ render :edit
64
+ end
65
+ end
66
+
67
+ def destroy
68
+ self.resource = find_resource
69
+ authorize(resource)
70
+ resource.destroy
71
+ redirect_to action: :index
72
+ end
73
+
74
+ private
75
+
76
+ def resource_class
77
+ Post
78
+ end
79
+
80
+ def resources
81
+ @posts
82
+ end
83
+
84
+ def resources=(models)
85
+ @posts = models
86
+ end
87
+
88
+ def resource
89
+ @post
90
+ end
91
+
92
+ def resource=(model)
93
+ @post = model
94
+ end
95
+
96
+ def list_resources
97
+ resource_class.all
98
+ end
99
+
100
+ def find_resource
101
+ resource_class.find(params[:id])
102
+ end
103
+
104
+ def new_resource
105
+ resource_class.new
106
+ end
107
+
108
+ def vest(model)
109
+ authorize(model)
110
+ model.assign_attributes(permitted_attributes(model))
111
+ model
112
+ end
113
+
114
+ end
115
+ ```
116
+
117
+ The implementations of the `resource_class` and `resource` / `resources`
118
+ accessor methods are generated based on the controller name. They can
119
+ be altered with an optional argument to the `garden_variety` macro. The
120
+ rest of the methods can be overridden as normal, a la carte. For a
121
+ detailed description of method behavior, see the
122
+ [full documentation](http://www.rubydoc.info/gems/garden_variety/).
123
+ (Note that the `authorize`, `policy_scope`, and `permitted_attributes`
124
+ methods are provided by Pundit.)
125
+
126
+
127
+ ## Scaffold generator
128
+
129
+ *garden_variety* includes a scaffold generator similar to the Rails
130
+ scaffold generator:
131
+
132
+ ```
133
+ $ rails generate garden:scaffold post title:string body:text published:boolean
134
+ generate resource
135
+ invoke active_record
136
+ create db/migrate/19991231235959_create_posts.rb
137
+ create app/models/post.rb
138
+ invoke test_unit
139
+ create test/models/post_test.rb
140
+ create test/fixtures/posts.yml
141
+ invoke controller
142
+ create app/controllers/posts_controller.rb
143
+ invoke erb
144
+ create app/views/posts
145
+ invoke test_unit
146
+ create test/controllers/posts_controller_test.rb
147
+ invoke helper
148
+ create app/helpers/posts_helper.rb
149
+ invoke test_unit
150
+ invoke assets
151
+ invoke coffee
152
+ create app/assets/javascripts/posts.coffee
153
+ invoke scss
154
+ create app/assets/stylesheets/posts.scss
155
+ invoke resource_route
156
+ route resources :posts
157
+ generate erb:scaffold
158
+ exist app/views/posts
159
+ create app/views/posts/index.html.erb
160
+ create app/views/posts/edit.html.erb
161
+ create app/views/posts/show.html.erb
162
+ create app/views/posts/new.html.erb
163
+ create app/views/posts/_form.html.erb
164
+ insert app/controllers/posts_controller.rb
165
+ generate pundit:policy
166
+ create app/policies/post_policy.rb
167
+ invoke test_unit
168
+ create test/policies/post_policy_test.rb
169
+ ```
170
+
171
+ The generated controller will contain only a call to the
172
+ `garden_variety` macro. Also, as you can see from the command output,
173
+ the *garden_variety* scaffold generator differs from the Rails scaffold
174
+ generator in a few small ways:
175
+
176
+ * No scaffold CSS (i.e. no "app/assets/stylesheets/scaffolds.scss").
177
+ * No jbuilder templates. Only HTML templates are generated.
178
+ * `rails generate pundit:policy` is invoked for the specified model.
179
+
180
+
181
+ ## Beyond garden variety behavior
182
+
183
+ *garden_variety* is designed to reduce the amount of custom code
184
+ written, including in situations where custom code is unavoidable.
185
+
186
+
187
+ ### Integrating with search
188
+
189
+ It is possible to integrate searching functionality by overriding the
190
+ `index` action. However, it can be simpler to override the
191
+ `list_resources` method instead:
192
+
193
+ ```ruby
194
+ class PostsController < ApplicationController
195
+ garden_variety
196
+
197
+ def list_resources
198
+ params[:author] ? super.where(author: params[:author]) : super
199
+ end
200
+ end
201
+ ```
202
+
203
+
204
+ ### Integrating with pagination
205
+
206
+ Your favorite pagination gem (*may I suggest
207
+ [foliate](https://rubygems.org/gems/foliate)?*) can also be integrated
208
+ by overriding the `list_resources` action:
209
+
210
+ ```ruby
211
+ class PostsController < ApplicationController
212
+ garden_variety
213
+
214
+ def list_resources
215
+ paginate(super)
216
+ end
217
+ end
218
+ ```
219
+
220
+
221
+ ### Integrating with authentication
222
+
223
+ The details of integrating authentication will depend on your chosen
224
+ authentication library. [Devise](https://rubygems.org/gems/devise) is a
225
+ popular gem, but I prefer [Clearance](https://rubygems.org/gems/clearance)
226
+ for its simplicity and concision. Whatever library you choose, it is
227
+ likely to include a "before filter" which you must invoke in your
228
+ controller to enforce authentication. Something similar to the
229
+ following:
230
+
231
+ ```ruby
232
+ class PostsController < ApplicationController
233
+ garden_variety
234
+ before_action :require_login
235
+ end
236
+ ```
237
+
238
+ Your authentication library is also likely to provide a `current_user`
239
+ method, which will return an appropriate value when the user is
240
+ authenticated. Pundit automatically uses this method to enforce
241
+ authorization policies. See your authentication library's documentation
242
+ to verify that it provides this method, or see Pundit's documentation
243
+ for details on using a different method to identify the current user.
244
+
245
+ *garden_variety* also provides a stub implementation of `current_user`,
246
+ so that if no authentication library is chosen, `current_user` will be
247
+ defined to always return nil.
248
+
249
+ **Note about Clearance:** Clearance versions previous to 2.0 define a
250
+ deprecated `authorize` method which conflicts with Pundit. To avoid
251
+ this conflict, add the following line to your ApplicationController or
252
+ Clearance initializer:
253
+
254
+ ```ruby
255
+ ::Clearance::Controller.send(:remove_method, :authorize)
256
+ ```
257
+
258
+
259
+ ### Integrating with Form Objects
260
+
261
+ The Form Object pattern is used to mitigate the complexity of handling
262
+ forms which need special processing logic, such as context-dependent
263
+ validation, or forms which involve more than one model. A detailed
264
+ explanation of the pattern is beyond the scope of this document, but
265
+ consider the following minimal example:
266
+
267
+ ```ruby
268
+ class RegistrationForm
269
+ include ActiveModel::Model
270
+
271
+ attr_accessor :email, :password, :accept_terms_of_service
272
+
273
+ validates :accept_terms_of_service, presence: true, acceptance: true
274
+
275
+ def save
276
+ @user = User.new(email: email, password: password)
277
+ if [valid?, @user.valid?].all?
278
+ @user.save
279
+ else
280
+ @user.errors.each{|attr, message| errors.add(attr, message) }
281
+ false
282
+ end
283
+ end
284
+ end
285
+
286
+
287
+ class RegistrationFormsController < ApplicationController
288
+ garden_variety :new
289
+
290
+ def create
291
+ self.resource = vest(new_resource)
292
+ if resource.save
293
+ redirect_to root_path # redirect to front page instead of show
294
+ else
295
+ render :new
296
+ end
297
+ end
298
+ end
299
+ ```
300
+
301
+ Only the `new` controller action is generated by the `garden_variety`
302
+ macro. The `create` action is implemented directly in order to redirect
303
+ to `root_path` rather than the resource itself, as would be
304
+ conventional. The *garden_variety* helper methods all work as expected
305
+ because `RegistrationForm` responds to `assign_attributes` and `save`,
306
+ and has a default (nullary) constructor.
307
+
308
+
309
+ ### Non-REST actions
310
+
311
+ You may also define any non-REST controller actions you wish (i.e.
312
+ actions other than: `index`, `show`, `new`, `create`, `edit`, `update`,
313
+ and `destroy`). The helper methods *garden_variety* provides may be
314
+ useful when doing so.
315
+
316
+ However, before implementing a non-REST controller action, consider if
317
+ the behavior might be better implemented as a REST action in a new
318
+ controller. For example, instead of the following `published` action...
319
+
320
+ ```ruby
321
+ class PostsController < ApplicationController
322
+ garden_variety
323
+
324
+ def published
325
+ @posts = Post.where(published: true)
326
+ render :index
327
+ end
328
+ end
329
+ ```
330
+
331
+ ...consider a new controller:
332
+
333
+ ```ruby
334
+ class PublishedPostsController < ApplicationController
335
+ garden_variety :index, resources: :posts
336
+
337
+ def list_resources
338
+ super.where(published: true)
339
+ end
340
+ end
341
+ ```
342
+
343
+ Note the `resources:` argument to the `garden_variety` macro. The
344
+ resource class for `PublishedPostsController` will be overridden as
345
+ `Post` instead of derived as `PublishedPost`. Likewise, the `@posts`
346
+ instance variable will be used instead of `@published_posts`.
347
+
348
+ This example may be somewhat contrived, but there is an excellent talk
349
+ from RailsConf which delves deeper into the principle:
350
+ [In Relentless Pursuit of REST](https://www.youtube.com/watch?v=HctYHe-YjnE).
351
+
352
+
353
+ ## Installation
354
+
355
+ Add this line to your application's Gemfile:
356
+
357
+ ```ruby
358
+ gem "garden_variety"
359
+ ```
360
+
361
+ Then execute:
362
+
363
+ ```bash
364
+ $ bundle
365
+ ```
366
+
367
+ And finally, if you haven't already used and installed Pundit, run the
368
+ Pundit installation generator:
369
+
370
+ ```bash
371
+ $ rails generate pundit:install
372
+ ```
373
+
374
+
375
+ ## Contributing
376
+
377
+ Run `rake test` to run the tests.
378
+
379
+
380
+ ## License
381
+
382
+ [MIT License](https://opensource.org/licenses/MIT)
data/Rakefile ADDED
@@ -0,0 +1,29 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'yard'
8
+
9
+ YARD::Rake::YardocTask.new(:doc) do |t|
10
+ end
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+ require 'bundler/gem_tasks'
19
+
20
+ require 'rake/testtask'
21
+
22
+ Rake::TestTask.new(:test) do |t|
23
+ t.libs << 'test'
24
+ t.pattern = 'test/**/*_test.rb'
25
+ t.verbose = false
26
+ end
27
+
28
+
29
+ task default: :test
@@ -0,0 +1,89 @@
1
+ module GardenVariety
2
+
3
+ module IndexAction
4
+ # Garden variety controller +index+ action.
5
+ # @return [void]
6
+ def index
7
+ authorize(resource_class)
8
+ self.resources = policy_scope(list_resources)
9
+ end
10
+ end
11
+
12
+ module ShowAction
13
+ # Garden variety controller +show+ action.
14
+ # @return [void]
15
+ def show
16
+ self.resource = find_resource
17
+ authorize(resource)
18
+ end
19
+ end
20
+
21
+ module NewAction
22
+ # Garden variety controller +new+ action.
23
+ # @return [void]
24
+ def new
25
+ self.resource = new_resource
26
+ authorize(resource)
27
+ end
28
+ end
29
+
30
+ module CreateAction
31
+ # Garden variety controller +create+ action.
32
+ # @return [void]
33
+ def create
34
+ self.resource = vest(new_resource)
35
+ if resource.save
36
+ redirect_to resource
37
+ else
38
+ render :new
39
+ end
40
+ end
41
+ end
42
+
43
+ module EditAction
44
+ # Garden variety controller +edit+ action.
45
+ # @return [void]
46
+ def edit
47
+ self.resource = find_resource
48
+ authorize(resource)
49
+ end
50
+ end
51
+
52
+ module UpdateAction
53
+ # Garden variety controller +update+ action.
54
+ # @return [void]
55
+ def update
56
+ self.resource = vest(find_resource)
57
+ if resource.save
58
+ redirect_to resource
59
+ else
60
+ render :edit
61
+ end
62
+ end
63
+ end
64
+
65
+ module DestroyAction
66
+ # Garden variety controller +destroy+ action.
67
+ # @return [void]
68
+ def destroy
69
+ self.resource = find_resource
70
+ authorize(resource)
71
+ resource.destroy
72
+ redirect_to action: :index
73
+ end
74
+ end
75
+
76
+ # Map of controller action name to action module. Used by the
77
+ # {GardenVariety::Controller::ClassMethods#garden_variety} macro to
78
+ # include desired controller actions.
79
+ ACTION_MODULES = {
80
+ index: IndexAction,
81
+ show: ShowAction,
82
+ new: NewAction,
83
+ create: CreateAction,
84
+ edit: EditAction,
85
+ update: UpdateAction,
86
+ destroy: DestroyAction,
87
+ }
88
+
89
+ end
@@ -0,0 +1,226 @@
1
+ require "pundit"
2
+ require "garden_variety/actions"
3
+
4
+ module GardenVariety
5
+ module Controller
6
+ extend ActiveSupport::Concern
7
+
8
+ include Pundit
9
+
10
+ module ClassMethods
11
+ # Macro to include garden variety implementations of specified
12
+ # actions in the controller. If no actions are specified, all
13
+ # typical REST actions (index, show, new, create, edit, update,
14
+ # destroy) are included.
15
+ #
16
+ # The optional +resources:+ parameter dictates which model class
17
+ # and instance variables these actions use. The parameter's
18
+ # default value derives from the controller name. The value must
19
+ # be a resource name in plural form.
20
+ #
21
+ # The macro also defines the following accessor methods for use in
22
+ # generic action and helper methods: +resources+, +resources=+,
23
+ # +resource+, and +resource=+. These accessors get and set the
24
+ # instance variables dictated by the +resources:+ parameter.
25
+ #
26
+ # @example default usage
27
+ # # This...
28
+ # class PostsController < ApplicationController
29
+ # garden_variety
30
+ # end
31
+ #
32
+ # # ...is equivalent to:
33
+ # class PostsController < ApplicationController
34
+ # include GardenVariety::IndexAction
35
+ # include GardenVariety::ShowAction
36
+ # include GardenVariety::NewAction
37
+ # include GardenVariety::CreateAction
38
+ # include GardenVariety::EditAction
39
+ # include GardenVariety::UpdateAction
40
+ # include GardenVariety::DestroyAction
41
+ #
42
+ # private
43
+ #
44
+ # def resource_class
45
+ # Post
46
+ # end
47
+ #
48
+ # def resources
49
+ # @posts
50
+ # end
51
+ #
52
+ # def resources=(models)
53
+ # @posts = models
54
+ # end
55
+ #
56
+ # def resource
57
+ # @post
58
+ # end
59
+ #
60
+ # def resource=(model)
61
+ # @post = model
62
+ # end
63
+ # end
64
+ #
65
+ # @example custom usage
66
+ # # This...
67
+ # class CountriesController < ApplicationController
68
+ # garden_variety :index, resources: :locations
69
+ # end
70
+ #
71
+ # # ...is equivalent to:
72
+ # class CountriesController < ApplicationController
73
+ # include GardenVariety::IndexAction
74
+ #
75
+ # private
76
+ #
77
+ # def resource_class
78
+ # Location
79
+ # end
80
+ #
81
+ # def resources
82
+ # @locations
83
+ # end
84
+ #
85
+ # def resources=(models)
86
+ # @locations = models
87
+ # end
88
+ #
89
+ # def resource
90
+ # @location
91
+ # end
92
+ #
93
+ # def resource=(model)
94
+ # @location = model
95
+ # end
96
+ # end
97
+ #
98
+ # @param actions [Array<:index, :show, :new, :create, :edit, :update, :destroy>]
99
+ # @param resources [Symbol, String]
100
+ # @return [void]
101
+ def garden_variety(*actions, resources: controller_name)
102
+ class_eval <<-CODE
103
+ private
104
+
105
+ def resource_class # optimized override
106
+ #{resources.to_s.classify}
107
+ end
108
+
109
+ def resources
110
+ @#{resources.to_s.underscore}
111
+ end
112
+
113
+ def resources=(models)
114
+ @#{resources.to_s.underscore} = models
115
+ end
116
+
117
+ def resource
118
+ @#{resources.to_s.underscore.singularize}
119
+ end
120
+
121
+ def resource=(model)
122
+ @#{resources.to_s.underscore.singularize} = model
123
+ end
124
+ CODE
125
+
126
+ action_modules = actions.empty? ?
127
+ ::GardenVariety::ACTION_MODULES.values :
128
+ ::GardenVariety::ACTION_MODULES.values_at(*actions)
129
+
130
+ action_modules.each{|m| include m }
131
+ end
132
+ end
133
+
134
+
135
+ private
136
+
137
+ # @!visibility public
138
+ # Returns the class of the resource corresponding to the controller
139
+ # name.
140
+ #
141
+ # @example
142
+ # PostsController.new.resource_class # == Post (class)
143
+ #
144
+ # @return [Class]
145
+ def resource_class
146
+ @resource_class ||= controller_name.classify.constantize
147
+ end
148
+
149
+ # @!visibility public
150
+ # Returns an ActiveRecord::Relation representing resource instances
151
+ # corresponding to the controller. Designed for use in generic
152
+ # +index+ action methods.
153
+ #
154
+ # @example
155
+ # class PostsController < ApplicationController
156
+ # def index
157
+ # @posts = list_resources.where(status: "published")
158
+ # end
159
+ # end
160
+ #
161
+ # @return [ActiveRecord::Relation]
162
+ def list_resources
163
+ resource_class.all
164
+ end
165
+
166
+ # @!visibility public
167
+ # Returns a model instance corresponding to the controller and the
168
+ # id parameter of the current request (i.e. +params[:id]+).
169
+ # Designed for use in generic +show+, +edit+, +update+, and
170
+ # +destroy+ action methods.
171
+ #
172
+ # @example
173
+ # class PostsController < ApplicationController
174
+ # def show
175
+ # @post = find_resource
176
+ # end
177
+ # end
178
+ #
179
+ # @return [ActiveRecord::Base]
180
+ def find_resource
181
+ resource_class.find(params[:id])
182
+ end
183
+
184
+ # @!visibility public
185
+ # Returns a new model instance corresponding to the controller.
186
+ # Designed for use in generic +new+ and +create+ action methods.
187
+ #
188
+ # @example
189
+ # class PostsController < ApplicationController
190
+ # def new
191
+ # @post = new_resource
192
+ # end
193
+ # end
194
+ #
195
+ # @return [ActiveRecord::Base]
196
+ def new_resource
197
+ resource_class.new
198
+ end
199
+
200
+ # @!visibility public
201
+ # Authorizes the given model for the current action via the model
202
+ # Pundit policy, and populates the model attributes with the current
203
+ # request params permitted by the model policy. Returns the given
204
+ # model modified but not persisted.
205
+ #
206
+ # @example
207
+ # class PostsController < ApplicationController
208
+ # def create
209
+ # @post = vest(Post.new)
210
+ # if @post.save
211
+ # redirect_to @post
212
+ # else
213
+ # render :new
214
+ # end
215
+ # end
216
+ # end
217
+ #
218
+ # @param model [ActiveRecord::Base]
219
+ # @return [ActiveRecord::Base]
220
+ def vest(model)
221
+ authorize(model)
222
+ model.assign_attributes(permitted_attributes(model))
223
+ model
224
+ end
225
+ end
226
+ end
@@ -0,0 +1,8 @@
1
+ module GardenVariety
2
+ # @!visibility private
3
+ module CurrentUserStub
4
+ def current_user
5
+ nil
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,29 @@
1
+ require "rails/railtie"
2
+ require "garden_variety/controller"
3
+ require "garden_variety/current_user_stub"
4
+
5
+ module GardenVariety
6
+ # @!visibility private
7
+ class Railtie < Rails::Railtie
8
+ # Render 404 on Pundit::NotAuthorizedError in production. (Helpful
9
+ # error pages will still be shown in development.) Code 404 is used
10
+ # because it is more discreet than 403, because it is explicitly
11
+ # allowed by RFC7231 (https://tools.ietf.org/html/rfc7231#section-6.5.3),
12
+ # and because Rails includes a default 404 page, but not a 403 page.
13
+ config.action_dispatch.rescue_responses["Pundit::NotAuthorizedError"] ||= :not_found
14
+
15
+ initializer "garden_variety.stub_current_user" do |app|
16
+ ActiveSupport.on_load :action_controller do
17
+ unless ActionController::Base.instance_methods.include?(:current_user)
18
+ ActionController::Base.send :include, GardenVariety::CurrentUserStub
19
+ end
20
+ end
21
+ end
22
+
23
+ initializer "garden_variety.extend_action_controller" do |app|
24
+ ActiveSupport.on_load :action_controller do
25
+ ActionController::Base.send :include, GardenVariety::Controller
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,3 @@
1
+ module GardenVariety
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,2 @@
1
+ require "garden_variety/version"
2
+ require "garden_variety/railtie"
@@ -0,0 +1,39 @@
1
+ require "rails/generators/base"
2
+
3
+ # @!visibility private
4
+ module Garden
5
+ module Generators
6
+ class ScaffoldGenerator < Rails::Generators::Base
7
+ argument :resource, type: :string
8
+
9
+ # NOTE: an appropriate default value for template_engine (e.g.
10
+ # :erb, or with the proper gem installed, :slim or :haml) is
11
+ # inherited from Rails::Generators::Base
12
+ class_option :template_engine
13
+
14
+ # override +initialize+ because it is the only way to reliably
15
+ # capture the raw input arguments in order to pass them on to
16
+ # `rails generate resource` (Thor neglects to provide an accessor,
17
+ # and ARGV is not populated during unit tests)
18
+ def initialize(raw_args, raw_opts, config)
19
+ @argv = raw_args + raw_opts
20
+ super
21
+ end
22
+
23
+ def generate_scaffolding
24
+ generate("resource", *@argv)
25
+ generate("#{options[:template_engine]}:scaffold", *@argv)
26
+ end
27
+
28
+ def inject_garden_variety_into_controller
29
+ inject_into_class("app/controllers/#{resource.tableize}_controller.rb",
30
+ "#{resource.tableize.camelize}Controller",
31
+ " garden_variety\n")
32
+ end
33
+
34
+ def generate_pundit_policy
35
+ generate("pundit:policy", resource)
36
+ end
37
+ end
38
+ end
39
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: garden_variety
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Jonathan Hefner
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-11-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 5.1.4
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 5.1.4
27
+ - !ruby/object:Gem::Dependency
28
+ name: pundit
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: sqlite3
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: yard
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.9'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.9'
69
+ description:
70
+ email:
71
+ - jonathan.hefner@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - MIT-LICENSE
77
+ - README.md
78
+ - Rakefile
79
+ - lib/garden_variety.rb
80
+ - lib/garden_variety/actions.rb
81
+ - lib/garden_variety/controller.rb
82
+ - lib/garden_variety/current_user_stub.rb
83
+ - lib/garden_variety/railtie.rb
84
+ - lib/garden_variety/version.rb
85
+ - lib/generators/garden/scaffold/scaffold_generator.rb
86
+ homepage: https://github.com/jonathanhefner/garden_variety
87
+ licenses:
88
+ - MIT
89
+ metadata: {}
90
+ post_install_message:
91
+ rdoc_options: []
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ requirements: []
105
+ rubyforge_project:
106
+ rubygems_version: 2.6.13
107
+ signing_key:
108
+ specification_version: 4
109
+ summary: Delightfully boring Rails controllers
110
+ test_files: []