rest_framework 0.0.16 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 825e7e7ac0e9c8ae57250288a54dc3ef6510665ce3d4fee23245c559aa8e8233
4
- data.tar.gz: 2211c303d14708ef94a4cb35d6e3b25bf78b3b08645f2990ca5448354d8dd64e
3
+ metadata.gz: 46db4e7aa05600caaa4c1f9f645f417b4d3cd9e5bcde7da0b54d3c5fa84e872e
4
+ data.tar.gz: 95c9d018b687795f80c38b43289f19ffd44eb1b170d883c164b590ab6b1c20d0
5
5
  SHA512:
6
- metadata.gz: 0ee2cf406f2b8d77d9ea63650b080d037a759143e0a3e19846585d493a386a4647db0fe59188aa0fd887257a18087aaca82b80d99dee962af1dfdb7eca66a07c
7
- data.tar.gz: 6248caea5ad7f5a37a55f7da6aae55c70dc284b9f04d046fc6149a13dff4ae34410106c97f54274f59a8353c79fe97073b7dcba51d65d9c94eb0f9cff1a205ac
6
+ metadata.gz: 2c376d191ffa5ae9de932dceb8411362a00be789ff9aa3733f038608da890fc5437d981576e3b17d402b857f7966cb15e437d7cbe2c8447191088a9a2249134f
7
+ data.tar.gz: 72e31acb2e66c6d8d2af2dd7375e7732a93b5e66b1c1fedf4c1d781421422c582958d32c6022305cd9cc2ca9dda51e2c2f6c540b1737e11eb3506501ef91b618
data/README.md CHANGED
@@ -117,4 +117,5 @@ $ rake test
117
117
  ```
118
118
 
119
119
  To interact with the test app, `cd test` and operate it via the normal Rails interfaces. Ensure you
120
- run `rake db:schema:load` before running `rails server` or `rails console`.
120
+ run `rake db:schema:load` before running `rails server` or `rails console`. You can also load the
121
+ test fixtures with `rake db:fixtures:load`.
@@ -1 +1 @@
1
- 0.0.16
1
+ 0.1.0
@@ -36,8 +36,6 @@ module RESTFramework
36
36
  extra_actions: nil,
37
37
  extra_member_actions: nil,
38
38
  filter_backends: nil,
39
- native_serializer_config: nil,
40
- native_serializer_action_config: nil,
41
39
  paginator_class: nil,
42
40
  page_size: nil,
43
41
  page_query_param: 'page',
@@ -77,17 +75,12 @@ module RESTFramework
77
75
 
78
76
  # Helper to get filtering backends with a sane default.
79
77
  def get_filter_backends
80
- if self.class.filter_backends
81
- return self.class.filter_backends
82
- end
83
-
84
- # By default, return nil.
85
- return nil
78
+ return self.class.filter_backends || []
86
79
  end
87
80
 
88
81
  # Filter the recordset over all configured filter backends.
89
82
  def get_filtered_data(data)
90
- (self.get_filter_backends || []).each do |filter_class|
83
+ self.get_filter_backends.each do |filter_class|
91
84
  filter = filter_class.new(controller: self)
92
85
  data = filter.get_filtered_data(data)
93
86
  end
@@ -95,9 +88,9 @@ module RESTFramework
95
88
  return data
96
89
  end
97
90
 
98
- # Helper to get the configured serializer class, or `NativeModelSerializer` as a default.
91
+ # Helper to get the configured serializer class.
99
92
  def get_serializer_class
100
- return self.class.serializer_class || NativeModelSerializer
93
+ return self.class.serializer_class
101
94
  end
102
95
 
103
96
  # Get a native serializer config for the current action.
@@ -23,6 +23,10 @@ module RESTFramework
23
23
  fields: nil,
24
24
  action_fields: nil,
25
25
 
26
+ # Attributes for the default native serializer.
27
+ native_serializer_config: nil,
28
+ native_serializer_action_config: nil,
29
+
26
30
  # Attributes for default model filtering (and ordering).
27
31
  filterset_fields: nil,
28
32
  ordering_fields: nil,
@@ -44,6 +48,11 @@ module RESTFramework
44
48
 
45
49
  protected
46
50
 
51
+ # Helper to get the configured serializer class, or `NativeModelSerializer` as a default.
52
+ def get_serializer_class
53
+ return self.class.serializer_class || RESTFramework::NativeModelSerializer
54
+ end
55
+
47
56
  # Get a list of parameters allowed for the current action.
48
57
  def get_allowed_parameters
49
58
  allowed_action_parameters = self.class.allowed_action_parameters || {}
@@ -57,11 +66,9 @@ module RESTFramework
57
66
 
58
67
  # Get the list of filtering backends to use.
59
68
  def get_filter_backends
60
- backends = super
61
- return backends if backends
62
-
63
- # By default, return the standard model filter backend.
64
- return [RESTFramework::ModelFilter, RESTFramework::ModelOrderingFilter]
69
+ return self.class.filter_backends || [
70
+ RESTFramework::ModelFilter, RESTFramework::ModelOrderingFilter
71
+ ]
65
72
  end
66
73
 
67
74
  # Get a list of fields for the current action.
@@ -76,14 +83,14 @@ module RESTFramework
76
83
  end
77
84
 
78
85
  # Filter the request body for keys in current action's allowed_parameters/fields config.
79
- def _get_parameter_values_from_request_body
86
+ def get_body_params
80
87
  fields = self.get_allowed_parameters || self.get_fields
81
- return @_get_parameter_values_from_request_body ||= (request.request_parameters.select { |p|
88
+ return @get_body_params ||= (request.request_parameters.select { |p|
82
89
  fields.include?(p.to_sym) || fields.include?(p.to_s)
83
90
  })
84
91
  end
85
- alias :get_create_params :_get_parameter_values_from_request_body
86
- alias :get_update_params :_get_parameter_values_from_request_body
92
+ alias :get_create_params :get_body_params
93
+ alias :get_update_params :get_body_params
87
94
 
88
95
  # Get a record by `id` or return a single record if recordset is filtered down to a single
89
96
  # record.
@@ -11,7 +11,7 @@ module RESTFramework
11
11
  @page_size = self._page_size
12
12
 
13
13
  @total_pages = @count / @page_size
14
- @total_pages += 1 if @count % @page_size
14
+ @total_pages += 1 if (@count % @page_size != 0)
15
15
  end
16
16
 
17
17
  def _page_size
@@ -2,6 +2,41 @@ require 'action_dispatch/routing/mapper'
2
2
 
3
3
  module ActionDispatch::Routing
4
4
  class Mapper
5
+ # Helper to take extra_actions hash and convert to a consistent format.
6
+ protected def _parse_extra_actions(extra_actions)
7
+ return (extra_actions || {}).map do |k,v|
8
+ kwargs = {}
9
+ path = k
10
+
11
+ # Convert structure to path/methods/kwargs.
12
+ if v.is_a?(Hash) # allow kwargs
13
+ v = v.symbolize_keys
14
+
15
+ # Ensure methods is an array.
16
+ if v[:methods].is_a?(String) || v[:methods].is_a?(Symbol)
17
+ methods = [v.delete(:methods)]
18
+ else
19
+ methods = v.delete(:methods)
20
+ end
21
+
22
+ # Override path if it's provided.
23
+ if v.key?(:path)
24
+ path = v.delete(:path)
25
+ end
26
+
27
+ # Pass any further kwargs to the underlying Rails interface.
28
+ kwargs = kwargs.merge(v)
29
+ elsif v.is_a?(Symbol) || v.is_a?(String)
30
+ methods = [v]
31
+ else
32
+ methods = v
33
+ end
34
+
35
+ # Return a hash with keys: :path, :methods, :kwargs.
36
+ {path: path, methods: methods, kwargs: kwargs}
37
+ end
38
+ end
39
+
5
40
  # Private interface to get the controller class from the name and current scope.
6
41
  protected def _get_controller_class(name, pluralize: true, fallback_reverse_pluralization: true)
7
42
  # get class name
@@ -40,16 +75,16 @@ module ActionDispatch::Routing
40
75
  # @param default_singular [Boolean] the default plurality of the resource if the plurality is
41
76
  # not otherwise defined by the controller
42
77
  # @param name [Symbol] the resource name, from which path and controller are deduced by default
43
- # @param skip_undefined [Boolean] whether we should skip routing undefined actions
78
+ # @param skip_undefined [Boolean] whether we should skip routing undefined resourceful actions
44
79
  protected def _rest_resources(default_singular, name, skip_undefined: true, **kwargs, &block)
45
- controller = kwargs[:controller] || name
80
+ controller = kwargs.delete(:controller) || name
46
81
  if controller.is_a?(Class)
47
82
  controller_class = controller
48
83
  else
49
84
  controller_class = _get_controller_class(controller, pluralize: !default_singular)
50
85
  end
51
86
 
52
- # set controller if it's not explicitly set
87
+ # Set controller if it's not explicitly set.
53
88
  kwargs[:controller] = name unless kwargs[:controller]
54
89
 
55
90
  # determine plural/singular resource
@@ -70,25 +105,20 @@ module ActionDispatch::Routing
70
105
  public_send(resource_method, name, except: skip, **kwargs) do
71
106
  if controller_class.respond_to?(:extra_member_actions)
72
107
  member do
73
- actions = controller_class.extra_member_actions || {}
74
- actions = actions.select { |k,v| controller_class.method_defined?(k) } if skip_undefined
75
- actions.each do |action, methods|
76
- methods = [methods] if methods.is_a?(Symbol) || methods.is_a?(String)
77
- methods.each do |m|
78
- public_send(m, action)
108
+ actions = self._parse_extra_actions(controller_class.extra_member_actions)
109
+ actions.each do |action_config|
110
+ action_config[:methods].each do |m|
111
+ public_send(m, action_config[:path], **action_config[:kwargs])
79
112
  end
80
113
  end
81
114
  end
82
115
  end
83
116
 
84
117
  collection do
85
- actions = controller_class.extra_actions || {}
86
- actions = actions.select { |k,v| controller_class.method_defined?(k) } if skip_undefined
87
- actions.reject! { |k,v| skip.include? k }
88
- actions.each do |action, methods|
89
- methods = [methods] if methods.is_a?(Symbol) || methods.is_a?(String)
90
- methods.each do |m|
91
- public_send(m, action)
118
+ actions = self._parse_extra_actions(controller_class.extra_actions)
119
+ actions.each do |action_config|
120
+ action_config[:methods].each do |m|
121
+ public_send(m, action_config[:path], **action_config[:kwargs])
92
122
  end
93
123
  end
94
124
  end
@@ -112,42 +142,55 @@ module ActionDispatch::Routing
112
142
  end
113
143
 
114
144
  # Route a controller without the default resourceful paths.
115
- def rest_route(path=nil, skip_undefined: true, **kwargs, &block)
116
- controller = kwargs.delete(:controller) || path
117
- path = path.to_s
145
+ def rest_route(name=nil, **kwargs, &block)
146
+ controller = kwargs.delete(:controller) || name
147
+ if controller.is_a?(Class)
148
+ controller_class = controller
149
+ else
150
+ controller_class = self._get_controller_class(controller, pluralize: false)
151
+ end
118
152
 
119
- # route actions
120
- controller_class = self._get_controller_class(controller, pluralize: false)
121
- skip = controller_class.get_skip_actions(skip_undefined: skip_undefined)
122
- actions = controller_class.extra_actions || {}
123
- actions = actions.select { |k,v| controller_class.method_defined?(k) } if skip_undefined
124
- actions.reject! { |k,v| skip.include? k }
125
- actions.each do |action, methods|
126
- methods = [methods] if methods.is_a?(Symbol) || methods.is_a?(String)
127
- methods.each do |m|
128
- public_send(m, File.join(path, action.to_s), controller: controller, action: action)
153
+ # Set controller if it's not explicitly set.
154
+ kwargs[:controller] = name unless kwargs[:controller]
155
+
156
+ # Route actions using the resourceful router, but skip all builtin actions.
157
+ actions = self._parse_extra_actions(controller_class.extra_actions)
158
+ public_send(:resource, name, only: [], **kwargs) do
159
+ actions.each do |action_config|
160
+ action_config[:methods].each do |m|
161
+ public_send(m, action_config[:path], **action_config[:kwargs])
162
+ end
163
+ yield if block_given?
129
164
  end
130
- yield if block_given?
131
165
  end
132
166
  end
133
167
 
134
168
  # Route a controller's `#root` to '/' in the current scope/namespace, along with other actions.
135
169
  # @param label [Symbol] the snake_case name of the controller
136
- def rest_root(path=nil, **kwargs, &block)
137
- # by default, use RootController#root
170
+ def rest_root(name=nil, **kwargs, &block)
171
+ # By default, use RootController#root.
138
172
  root_action = kwargs.delete(:action) || :root
139
- controller = kwargs.delete(:controller) || path || :root
140
- path = path.to_s
173
+ controller = kwargs.delete(:controller) || name || :root
141
174
 
142
- # route the root
143
- get path, controller: controller, action: root_action
175
+ # Route the root.
176
+ get name.to_s, controller: controller, action: root_action
144
177
 
145
- # route any additional actions
178
+ # Route any additional actions.
146
179
  controller_class = self._get_controller_class(controller, pluralize: false)
147
- (controller_class.extra_actions || {}).each do |action, methods|
148
- methods = [methods] if methods.is_a?(Symbol) || methods.is_a?(String)
149
- methods.each do |m|
150
- public_send(m, File.join(path, action.to_s), controller: controller, action: action)
180
+ actions = self._parse_extra_actions(controller_class.extra_actions)
181
+ actions.each do |action_config|
182
+ # Add :action unless kwargs defines it.
183
+ unless action_config[:kwargs].key?(:action)
184
+ action_config[:kwargs][:action] = action_config[:path]
185
+ end
186
+
187
+ action_config[:methods].each do |m|
188
+ public_send(
189
+ m,
190
+ File.join(name.to_s, action_config[:path].to_s),
191
+ controller: controller,
192
+ **action_config[:kwargs],
193
+ )
151
194
  end
152
195
  yield if block_given?
153
196
  end
@@ -8,18 +8,25 @@ module RESTFramework
8
8
  end
9
9
  end
10
10
 
11
- # This serializer uses `.as_json` to serialize objects. Despite the name, `.as_json` is a Rails
12
- # method which converts objects to Ruby primitives (with the top-level being either an array or a
13
- # hash).
14
- class NativeSerializer < BaseSerializer
11
+ # This serializer uses `.as_json` to serialize objects. Despite the name, `.as_json` is an
12
+ # `ActiveModel` method which converts objects to Ruby primitives (with the top-level being either
13
+ # an array or a hash).
14
+ class NativeModelSerializer < BaseSerializer
15
15
  class_attribute :config
16
16
  class_attribute :singular_config
17
17
  class_attribute :plural_config
18
18
  class_attribute :action_config
19
19
 
20
- def initialize(many: nil, **kwargs)
20
+ def initialize(many: nil, model: nil, **kwargs)
21
21
  super(**kwargs)
22
- @many = many
22
+
23
+ if many.nil?
24
+ @many = @object.respond_to?(:count) ? @object.count : nil
25
+ else
26
+ @many = many
27
+ end
28
+
29
+ @model = model || (@controller ? @controller.send(:get_model) : nil)
23
30
  end
24
31
 
25
32
  # Get controller action, if possible.
@@ -58,6 +65,13 @@ module RESTFramework
58
65
  return serializer_config
59
66
  end
60
67
 
68
+ # If the config wasn't determined, build a serializer config from model fields.
69
+ fields = @controller.try(:get_fields) if @controller
70
+ unless fields.blank?
71
+ columns, methods = fields.partition { |f| f.to_s.in?(@model.column_names) }
72
+ return {only: columns, methods: methods}
73
+ end
74
+
61
75
  return {}
62
76
  end
63
77
 
@@ -99,27 +113,4 @@ module RESTFramework
99
113
  end
100
114
  end
101
115
 
102
- # `NativeModelSerializer` is similar to `NativeSerializer` but with some customizations to work
103
- # with `ActiveModel`.
104
- class NativeModelSerializer < NativeSerializer
105
- def initialize(model: nil, **kwargs)
106
- super(**kwargs)
107
- @model = model || (@controller ? @controller.send(:get_model) : nil)
108
- end
109
-
110
- # Get a configuration passable to `as_json` for the object.
111
- def get_serializer_config
112
- config = super
113
- return config unless config.blank?
114
-
115
- # If the config wasn't determined, build a serializer config from model fields.
116
- fields = @controller.try(:get_fields) if @controller
117
- unless fields.blank?
118
- columns, methods = fields.partition { |f| f.to_s.in?(@model.column_names) }
119
- return {only: columns, methods: methods}
120
- end
121
-
122
- return {}
123
- end
124
- end
125
116
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rest_framework
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.16
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gregory N. Schmit
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-07 00:00:00.000000000 Z
11
+ date: 2021-02-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -48,11 +48,11 @@ files:
48
48
  - lib/rest_framework/routers.rb
49
49
  - lib/rest_framework/serializers.rb
50
50
  - lib/rest_framework/version.rb
51
- homepage: https://github.com/gregschmit/rails-rest-framework
51
+ homepage: https://rails-rest-framework.com
52
52
  licenses:
53
53
  - MIT
54
54
  metadata:
55
- homepage_uri: https://github.com/gregschmit/rails-rest-framework
55
+ homepage_uri: https://rails-rest-framework.com
56
56
  source_code_uri: https://github.com/gregschmit/rails-rest-framework
57
57
  post_install_message:
58
58
  rdoc_options: []
@@ -70,7 +70,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
70
70
  - !ruby/object:Gem::Version
71
71
  version: '0'
72
72
  requirements: []
73
- rubygems_version: 3.0.8
73
+ rubygems_version: 3.0.9
74
74
  signing_key:
75
75
  specification_version: 4
76
76
  summary: A framework for DRY RESTful APIs in Ruby on Rails.