undercarriage 1.0.0 → 1.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 59a96756fb12afc085cd7e915c6c55d4795d354ba3e1206d2f2e4c600366f8ce
4
- data.tar.gz: 18b7f4c033a3c1e0ec2b15be8a648dd6dd8c44cb77ea3df455a63b7376aa1fc0
3
+ metadata.gz: b8d42d984572277bb1282c5fa0306028d91ced6801f88bb7ad36f01c05fcd8e8
4
+ data.tar.gz: f3d7690b1fdbf864395695f4a8651bbce2a907333430df01208edd0503419144
5
5
  SHA512:
6
- metadata.gz: 0b22d67b2f8fddc1b9b5ab58205557e56c2e8ed1e4087092f265252ba573fc111f121c34b403e255556b03abde62dfe8046cb17711662f8c13cb7a9aba762003
7
- data.tar.gz: b9c0d216a9c6e7455dad762f88dd13c953cc1dc251c4c3be6361b7d7e766882205878a52a923eaa81ace11762a09bd5cd3b670b85c8e3c0e07f4185513314097
6
+ metadata.gz: 6ee506e32efb9f323e4f5dcfd8494d00050dc0e20a9d4c09244440c0b7269cc52e5024878a91e24db6da67aa88908840931c0559d0ab7028f1a4cb7e932e61cc
7
+ data.tar.gz: 8577454663eaec4d8b20bd5f06bf36bc2d296cca855113e77b5f9b91c33908354f69aa33645e82ba14c3f45e154790008f4d2c309bf4943814ab5b2d8fd28078
data/README.md CHANGED
@@ -1,12 +1,10 @@
1
1
  # Undercarriage
2
2
 
3
- **\*Undercarriage is currently under development. It is not ready for production use.\***
4
-
5
3
  Undercarriage is a set of concerns to add to your application to trim some of the fat from controllers and models.
6
4
 
7
5
  ## Requirements
8
6
 
9
- * Ruby >= 3.3.0
7
+ * Ruby >= 3.0
10
8
  * Rails >= 6.0
11
9
 
12
10
  ## Installation
@@ -14,7 +12,7 @@ Undercarriage is a set of concerns to add to your application to trim some of th
14
12
  Add to your application's Gemfile
15
13
 
16
14
  ```bash
17
- gem 'undercarriage', '~> 1.0'
15
+ gem 'undercarriage', '~> 1.1'
18
16
  ```
19
17
 
20
18
  Run the bundle command
@@ -25,7 +23,37 @@ $ bundle install
25
23
 
26
24
  ## Usage
27
25
 
28
- TODO
26
+ Include `Undercarriage::Controllers::RestfulConcern` in a controller to get full RESTful `index`/`show`/`new`/`create`/`edit`/`update`/`destroy` actions, driven off the controller's own name/path:
27
+
28
+ ```ruby
29
+ class PostsController < ApplicationController
30
+ include Undercarriage::Controllers::RestfulConcern
31
+
32
+ private
33
+
34
+ def permitted_attributes
35
+ [:title, :body]
36
+ end
37
+ end
38
+ ```
39
+
40
+ This infers `Post` as the model, sets `@posts`/`@post` as appropriate, and wires up flash messages, strong params, and redirects with no further code. Override the `*_content` hooks (e.g. `show_content`, `create_content`) or `after_create_action`/`after_update_action` to customize a single action without redefining it — see the YARD docs on each `Undercarriage::Controllers::Restful::*` concern for the full hook list.
41
+
42
+ The standalone concerns can be included individually where you don't want the full RESTful stack:
43
+
44
+ ```ruby
45
+ class ExamplesController < ApplicationController
46
+ include Undercarriage::Controllers::ActionConcern # action?/index_action?/etc. view helpers
47
+ include Undercarriage::Controllers::KaminariConcern # page_num/per_page params for Kaminari
48
+ include Undercarriage::Controllers::LocaleConcern # I18n.locale from HTTP_ACCEPT_LANGUAGE
49
+ end
50
+
51
+ class Example < ApplicationRecord
52
+ include Undercarriage::Models::PublishedConcern # published/unpublished scopes
53
+ end
54
+ ```
55
+
56
+ See the YARD documentation linked below for every concern's options and examples.
29
57
 
30
58
  ## Testing
31
59
 
@@ -28,7 +28,8 @@ module Undercarriage
28
28
  # Items per page
29
29
  #
30
30
  # The number of items to return in pagination. Will use the Kaminari config `default_per_page` (typically `25`)
31
- # for the count and will look for `per` in the URL paramaters to override.
31
+ # for the count and will look for `per` in the URL paramaters to override. The result is clamped between `1`
32
+ # and {#per_page_max} so a caller cannot force an unbounded (or negative/zero) number of records per page.
32
33
  #
33
34
  # This is asseccible from the View as `per_page`
34
35
  #
@@ -37,14 +38,16 @@ module Undercarriage
37
38
  # @example Request
38
39
  # # GET /examples?per=100 # Return 100 items per page
39
40
  # # GET /examples?per=10&page=3 # Return page 3 of items with 10 items per page
41
+ # # GET /examples?per=999999999 # Clamped down to per_page_max
40
42
  def per_page
41
- params.fetch(per_page_key, per_page_default).to_i
43
+ params.fetch(per_page_key, per_page_default).to_i.clamp(1, per_page_max)
42
44
  end
43
45
 
44
46
  ##
45
47
  # Page number
46
48
  #
47
- # Will look for the Kaminari config `param_name` (typically `page`) in the URL paramaters.
49
+ # Will look for the Kaminari config `param_name` (typically `page`) in the URL paramaters. The result is
50
+ # clamped to a minimum of `1` so a caller cannot force a negative or zero page number.
48
51
  #
49
52
  # This is asseccible from the View as `page_num`
50
53
  #
@@ -54,7 +57,7 @@ module Undercarriage
54
57
  # # GET /examples?page=5 # Return page 5 of items
55
58
  # # GET /examples?per=10&page=3 # Return page 3 of items with 10 items per page
56
59
  def page_num
57
- params.fetch(page_num_key, page_num_default).to_i
60
+ params.fetch(page_num_key, page_num_default).to_i.clamp(1, nil)
58
61
  end
59
62
 
60
63
  protected
@@ -100,6 +103,17 @@ module Undercarriage
100
103
  def page_num_default
101
104
  1
102
105
  end
106
+
107
+ ##
108
+ # Items per page maximum
109
+ #
110
+ # Upper bound enforced on {#per_page} regardless of what the `per` query param requests. Defaults to the
111
+ # Kaminari config `max_per_page` when set, otherwise `100`. Override to allow a different ceiling.
112
+ #
113
+ # @return [Integer] maximum per page count
114
+ def per_page_max
115
+ Kaminari.config.max_per_page || 100
116
+ end
103
117
  end
104
118
  end
105
119
  end
@@ -37,16 +37,6 @@ module Undercarriage
37
37
  model_class
38
38
  end
39
39
 
40
- ##
41
- # New content action
42
- #
43
- # Decide what content to load based on action name
44
- #
45
- # @return [Object,Hash]
46
- def resource_new_content
47
- action_name == "new" ? new_resource_content : create_resource_content
48
- end
49
-
50
40
  ##
51
41
  # Resource action
52
42
  #
@@ -72,12 +62,52 @@ module Undercarriage
72
62
  # #
73
63
  # # authorize @example
74
64
  # # end
65
+ #
66
+ # ##
67
+ # # To override only a single action's query, override its `*_content` hook instead of `resource_content`
68
+ # # itself. The other actions keep using `resource_content`
69
+ # #
70
+ # # def show_content
71
+ # # super
72
+ # #
73
+ # # authorize @example
74
+ # # end
75
75
  # end
76
76
  def resource_content
77
77
  resource_id = params.fetch(:id)
78
- resource_query = model_class.find(resource_id)
78
+ resource_scope.find(resource_id)
79
+ end
80
+
81
+ ##
82
+ # Resource content for the `destroy` action
83
+ #
84
+ # @return [Object,Hash]
85
+ def destroy_content
86
+ resource_content
87
+ end
88
+
89
+ ##
90
+ # Resource content for the `edit` action
91
+ #
92
+ # @return [Object,Hash]
93
+ def edit_content
94
+ resource_content
95
+ end
79
96
 
80
- instance_variable_set("@#{instance_name}", resource_query)
97
+ ##
98
+ # Resource content for the `show` action
99
+ #
100
+ # @return [Object,Hash]
101
+ def show_content
102
+ resource_content
103
+ end
104
+
105
+ ##
106
+ # Resource content for the `update` action
107
+ #
108
+ # @return [Object,Hash]
109
+ def update_content
110
+ resource_content
81
111
  end
82
112
 
83
113
  ##
@@ -62,6 +62,14 @@ module Undercarriage
62
62
 
63
63
  protected
64
64
 
65
+ ##
66
+ # Create resource content
67
+ #
68
+ # @return [Object] the built resource
69
+ def create_content
70
+ resource_scope.new(create_resource_params)
71
+ end
72
+
65
73
  ##
66
74
  # Create restful action
67
75
  #
@@ -87,15 +95,16 @@ module Undercarriage
87
95
  # # end
88
96
  #
89
97
  # ##
90
- # # The `resource_new_content` method can also be overwritten. This method is meant to share content with
91
- # # the `new` action
98
+ # # To change the underlying build without touching instance variable assignment, override
99
+ # # `create_content` instead. Note this is independent from `new_content` (`create` no longer shares
100
+ # # this method with `new`)
92
101
  # #
93
- # # def resource_new_content
102
+ # # def create_content
94
103
  # # ...
95
104
  # # end
96
105
  # end
97
106
  def create_resource_content
98
- resource_query = resource_scope.new(create_resource_params)
107
+ resource_query = create_content
99
108
 
100
109
  instance_variable_set("@#{instance_name}", resource_query)
101
110
  end
@@ -109,7 +118,7 @@ module Undercarriage
109
118
  #
110
119
  # @return [Object] the built resource
111
120
  def create_resource
112
- @create_resource ||= resource_new_content
121
+ @create_resource ||= create_resource_content
113
122
  end
114
123
  end
115
124
  end
@@ -84,9 +84,17 @@ module Undercarriage
84
84
  # # def resource_content
85
85
  # # ...
86
86
  # # end
87
+ #
88
+ # ##
89
+ # # To change the query for `destroy` only, override `destroy_content` instead. The `show`, `edit` and
90
+ # # `update` actions are unaffected
91
+ # #
92
+ # # def destroy_content
93
+ # # ...
94
+ # # end
87
95
  # end
88
96
  def destroy_resource_content
89
- resource_content
97
+ instance_variable_set("@#{instance_name}", destroy_content)
90
98
  end
91
99
 
92
100
  private
@@ -76,9 +76,17 @@ module Undercarriage
76
76
  # # def resource_content
77
77
  # # ...
78
78
  # # end
79
+ #
80
+ # ##
81
+ # # To change the query for `edit` only, override `edit_content` instead. The `show`, `update` and
82
+ # # `destroy` actions are unaffected
83
+ # #
84
+ # # def edit_content
85
+ # # ...
86
+ # # end
79
87
  # end
80
88
  def edit_resource_content
81
- resource_content
89
+ instance_variable_set("@#{instance_name}", edit_content)
82
90
  end
83
91
 
84
92
  private
@@ -42,6 +42,14 @@ module Undercarriage
42
42
 
43
43
  protected
44
44
 
45
+ ##
46
+ # Index resource content
47
+ #
48
+ # @return [Object] resource collection scope
49
+ def index_content
50
+ resource_scope.all
51
+ end
52
+
45
53
  ##
46
54
  # Index restful action
47
55
  #
@@ -65,9 +73,17 @@ module Undercarriage
65
73
  # #
66
74
  # # authorize @examples
67
75
  # # end
76
+ #
77
+ # ##
78
+ # # To change the underlying query without touching instance variable assignment, override
79
+ # # `index_content` instead
80
+ # #
81
+ # # def index_content
82
+ # # ...
83
+ # # end
68
84
  # end
69
85
  def resources_content
70
- resources_query = resource_scope.all
86
+ resources_query = index_content
71
87
 
72
88
  instance_variable_set("@#{instances_name}", resources_query)
73
89
  end
@@ -45,6 +45,14 @@ module Undercarriage
45
45
 
46
46
  protected
47
47
 
48
+ ##
49
+ # New resource content
50
+ #
51
+ # @return [Object] the built resource
52
+ def new_content
53
+ resource_scope.new
54
+ end
55
+
48
56
  ##
49
57
  # New restful action
50
58
  #
@@ -70,15 +78,16 @@ module Undercarriage
70
78
  # # end
71
79
  #
72
80
  # ##
73
- # # The `resource_new_content` method can also be overwritten. This method is meant to share content with
74
- # # the `create` action
81
+ # # To change the underlying build without touching instance variable assignment, override
82
+ # # `new_content` instead. Note this is independent from `create_content` (`create` no longer shares
83
+ # # this method with `new`)
75
84
  # #
76
- # # def resource_new_content
85
+ # # def new_content
77
86
  # # ...
78
87
  # # end
79
88
  # end
80
89
  def new_resource_content
81
- resource_query = resource_scope.new
90
+ resource_query = new_content
82
91
 
83
92
  instance_variable_set("@#{instance_name}", resource_query)
84
93
  end
@@ -92,7 +101,7 @@ module Undercarriage
92
101
  #
93
102
  # @return [Object] the built resource
94
103
  def new_resource
95
- @new_resource ||= resource_new_content
104
+ @new_resource ||= new_resource_content
96
105
  end
97
106
  end
98
107
  end
@@ -73,9 +73,17 @@ module Undercarriage
73
73
  # # def resource_content
74
74
  # # ...
75
75
  # # end
76
+ #
77
+ # ##
78
+ # # To change the query for `show` only, override `show_content` instead. The `edit`, `update` and
79
+ # # `destroy` actions are unaffected
80
+ # #
81
+ # # def show_content
82
+ # # ...
83
+ # # end
76
84
  # end
77
85
  def show_resource_content
78
- resource_content
86
+ instance_variable_set("@#{instance_name}", show_content)
79
87
  end
80
88
 
81
89
  private
@@ -93,9 +93,17 @@ module Undercarriage
93
93
  # # def resource_content
94
94
  # # ...
95
95
  # # end
96
+ #
97
+ # ##
98
+ # # To change the query for `update` only, override `update_content` instead. The `show`, `edit` and
99
+ # # `destroy` actions are unaffected
100
+ # #
101
+ # # def update_content
102
+ # # ...
103
+ # # end
96
104
  # end
97
105
  def update_resource_content
98
- resource_content
106
+ instance_variable_set("@#{instance_name}", update_content)
99
107
  end
100
108
 
101
109
  private
@@ -3,5 +3,5 @@
3
3
  module Undercarriage
4
4
  ##
5
5
  # Undercarriage version
6
- VERSION = "1.0.0"
6
+ VERSION = "1.1.0"
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: undercarriage
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Freerksen