rest_framework 0.0.0 → 0.0.1

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: c71a3fea7904490cd834aff65231d4a18804e8cd487a07314e475a73d9a6500e
4
- data.tar.gz: bde5421c92b4c960bc9b09b369a36b2d4df463b0722490c35cbaf00cdb6b6a66
3
+ metadata.gz: 0ae8173bd8209fe5250ec9fe3a749d41d46307f7948d1c7597921ab5b4d2cae2
4
+ data.tar.gz: 3ca1aa88dbde70ad327a65778bfa7e2a90499111dbf6e16a9d084aba2df42328
5
5
  SHA512:
6
- metadata.gz: 21db95368e8223a1b086e63b9724eb7cb35cb5eb42db9eedb5eca557662be24363f225ab69fb98d2996152c69d58218a5156fdaba1345330660c974313b3f912
7
- data.tar.gz: 2f32d14d77eb8f60b29019afd81f6b926e2bd97268b2cd6d4828698adf4b66debea2959f00403913a6e74a970f858d960a4d3c9268a1f6fcccd9549c1aca992e
6
+ metadata.gz: bd56096773684dc55324b6a8d3fed2a7d214201fd9ac516862a24a111ecedcf70cebf20b61ff264f11a921d67e9a057da4a8b1c2d4c498d07bb042401993e5e3
7
+ data.tar.gz: 2f9f5b01fa4a956f0047307ed0f9b7523607ad6487fa5f8fa15d9895b7ff814703c048e5a7a0261fad35f11b96f3078641e8b9dd9e897bdbbc15b36c775c084e
data/README.md CHANGED
@@ -24,6 +24,78 @@ Or install it yourself with:
24
24
 
25
25
  $ gem install rest_framework
26
26
 
27
+ ## Usage
28
+
29
+ ### Controller Mixins
30
+
31
+ To transform a controller into a RESTful controller, you can either include `BaseControllerMixin`,
32
+ `ReadOnlyModelControllerMixin`, or `ModelControllerMixin`. `BaseControllerMixin` provides a `root`
33
+ action and a simple interface for routing arbitrary additional actions:
34
+
35
+ ```
36
+ class ApiController < ApplicationController
37
+ include RESTFramework::BaseControllerMixin
38
+ @extra_actions = {test: [:get]}
39
+
40
+ def test
41
+ render inline: "Test successful!"
42
+ end
43
+ end
44
+ ```
45
+
46
+ `ModelControllerMixin` assists with providing the standard CRUD for your controller.
47
+
48
+ ```
49
+ class Api::MoviesController < ApiController
50
+ include RESTFramework::ModelControllerMixin
51
+
52
+ @recordset = Movie.where(enabled: true) # by default, @recordset would include all movies
53
+ end
54
+ ```
55
+
56
+ `ReadOnlyModelControllerMixin` only enables list/show actions, but since we're naming this
57
+ controller in a way that doesn't make the model obvious, we can set that explicitly:
58
+
59
+ ```
60
+ class Api::ReadOnlyMoviesController < ApiController
61
+ include RESTFramework::ReadOnlyModelControllerMixin
62
+
63
+ @model = Movie
64
+ end
65
+ ```
66
+
67
+ Note that you can also override `get_model` and `get_recordset` instance methods to override the API
68
+ behavior based on each request.
69
+
70
+ ### Routing
71
+
72
+ You can use Rails' `resource`/`resources` routers to route your API, however if you want
73
+ `@extra_actions`/`@extra_member_actions` to be routed automatically, then you can use the
74
+ `rest_resource`/`rest_resources` routers provided by this gem. You can also use `rest_root` to route
75
+ the root of your API:
76
+
77
+ ```
78
+ Rails.application.routes.draw do
79
+ rest_root :api # will find `api_controller` and route the `root` action to '/api'
80
+ namespace :api do
81
+ rest_resources :movies
82
+ rest_resources :read_only_movies
83
+ end
84
+ end
85
+ ```
86
+
87
+ Or if you want the API root to be routed to `Api::RootController#root`:
88
+
89
+ ```
90
+ Rails.application.routes.draw do
91
+ namespace :api do
92
+ rest_root # will route `Api::RootController#root` to '/' in this namespace ('/api')
93
+ rest_resources :movies
94
+ rest_resources :read_only_movies
95
+ end
96
+ end
97
+ ```
98
+
27
99
  ## Development/Testing
28
100
 
29
101
  After you clone the repository, cd'ing into the directory should create a new gemset if you are
@@ -37,10 +109,10 @@ To run unit tests:
37
109
 
38
110
  $ rake test:unit
39
111
 
40
- To run integration tests on a sample app:
41
-
42
- $ rake test:app
112
+ To run integration tests:
43
113
 
44
- To run that sample app live:
114
+ $ rake test:integration
45
115
 
46
- $ rake test:app:run
116
+ To interact with the integration app, you can `cd test/integration` and operate it via the normal
117
+ Rails interfaces. Ensure you run `rake db:schema:load` before running `rails server` or
118
+ `rails console`.
@@ -1 +1 @@
1
- 0.0.0
1
+ 0.0.1
@@ -1,6 +1,9 @@
1
1
  module RESTFramework
2
2
 
3
+ # This module provides helpers for mixin `ClassMethods` submodules.
3
4
  module ClassMethodHelpers
5
+
6
+ # This helper assists in providing reader interfaces for mixin properties.
4
7
  def _restframework_attr_reader(property, default: nil)
5
8
  method = <<~RUBY
6
9
  def #{property}
@@ -14,6 +17,9 @@ module RESTFramework
14
17
  end
15
18
  end
16
19
 
20
+ # This module provides the common functionality for any controller mixins, a `root` action, and
21
+ # the ability to route arbitrary actions with `@extra_actions`. This is also where `api_response`
22
+ # is defined.
17
23
  module BaseControllerMixin
18
24
  # Default action for API root.
19
25
  # TODO: use api_response and show sub-routes.
@@ -47,7 +53,20 @@ module RESTFramework
47
53
  # end
48
54
 
49
55
  _restframework_attr_reader(:extra_actions, default: {})
50
- _restframework_attr_reader(:skip_actions, default: [])
56
+
57
+ def skip_actions(skip_undefined: true)
58
+ # first, skip explicitly skipped actions
59
+ skip = _restframework_try_class_level_variable_get(:skip_actions, default: [])
60
+
61
+ # now add methods which don't exist, since we don't want to route those
62
+ if skip_undefined
63
+ [:index, :new, :create, :show, :edit, :update, :destroy].each do |a|
64
+ skip << a unless self.method_defined?(a)
65
+ end
66
+ end
67
+
68
+ return skip
69
+ end
51
70
  end
52
71
 
53
72
  def self.included(base)
@@ -32,11 +32,14 @@ module RESTFramework
32
32
  _restframework_attr_reader(:extra_member_actions, default: {})
33
33
 
34
34
  # For model-based mixins, `@extra_collection_actions` is synonymous with `@extra_actions`.
35
- def extra_actions
36
- return (
35
+ # @param skip_undefined [Boolean] whether we should skip routing undefined actions
36
+ def extra_actions(skip_undefined: true)
37
+ actions = (
37
38
  _restframework_try_class_level_variable_get(:extra_collection_actions) ||
38
39
  _restframework_try_class_level_variable_get(:extra_actions, default: {})
39
40
  )
41
+ actions = actions.select { |a| self.method_defined?(a) } if skip_undefined
42
+ return actions
40
43
  end
41
44
  end
42
45
 
@@ -109,10 +112,10 @@ module RESTFramework
109
112
  end
110
113
 
111
114
  # Internal interface for get_model, protecting against infinite recursion with get_recordset.
112
- private def _get_model(from_internal_get_recordset: false)
115
+ def _get_model(from_internal_get_recordset: false)
113
116
  return @model if @model
114
117
  return self.class.model if self.class.model
115
- unless from_get_recordset # prevent infinite recursion
118
+ unless from_internal_get_recordset # prevent infinite recursion
116
119
  recordset = self._get_recordset(from_internal_get_model: true)
117
120
  return (@model = recordset.klass) if recordset
118
121
  end
@@ -124,10 +127,10 @@ module RESTFramework
124
127
  end
125
128
 
126
129
  # Internal interface for get_recordset, protecting against infinite recursion with get_model.
127
- private def _get_recordset(from_internal_get_model: false)
130
+ def _get_recordset(from_internal_get_model: false)
128
131
  return @recordset if @recordset
129
132
  return self.class.recordset if self.class.recordset
130
- unless from_get_model # prevent infinite recursion
133
+ unless from_internal_get_model # prevent infinite recursion
131
134
  model = self._get_model(from_internal_get_recordset: true)
132
135
  return (@recordset = model.all) if model
133
136
  end
@@ -41,7 +41,8 @@ module ActionDispatch::Routing
41
41
  # @param default_singular [Boolean] the default plurality of the resource if the plurality is
42
42
  # not otherwise defined by the controller
43
43
  # @param name [Symbol] the resource name, from which path and controller are deduced by default
44
- protected def _rest_resources(default_singular, name, **kwargs, &block)
44
+ # @param skip_undefined [Boolean] whether we should skip routing undefined actions
45
+ protected def _rest_resources(default_singular, name, skip_undefined: true, **kwargs, &block)
45
46
  controller = kwargs[:controller] || name
46
47
  if controller.is_a?(Class)
47
48
  controller_class = controller
@@ -50,9 +51,7 @@ module ActionDispatch::Routing
50
51
  end
51
52
 
52
53
  # set controller if it's not explicitly set
53
- unless kwargs[:controller]
54
- kwargs[:controller] = name
55
- end
54
+ kwargs[:controller] = name unless kwargs[:controller]
56
55
 
57
56
  # determine plural/singular resource
58
57
  if kwargs.delete(:force_singular)
@@ -67,10 +66,14 @@ module ActionDispatch::Routing
67
66
  resource_method = singular ? :resource : :resources
68
67
 
69
68
  # call either `resource` or `resources`, passing appropriate modifiers
70
- public_send(resource_method, name, except: controller_class.skip_actions, **kwargs) do
69
+ skip_undefined = kwargs.delete(:skip_undefined) || true
70
+ skip = controller_class.skip_actions(skip_undefined: skip_undefined)
71
+ public_send(resource_method, name, except: skip, **kwargs) do
71
72
  if controller_class.respond_to?(:extra_member_actions)
72
73
  member do
73
- controller_class.extra_member_actions.each do |action, methods|
74
+ actions = controller_class.extra_member_actions
75
+ actions = actions.select { |k,v| controller_class.method_defined?(k) } if skip_undefined
76
+ actions.each do |action, methods|
74
77
  methods = [methods] if methods.is_a?(Symbol) || methods.is_a?(String)
75
78
  methods.each do |m|
76
79
  public_send(m, action)
@@ -80,7 +83,9 @@ module ActionDispatch::Routing
80
83
  end
81
84
 
82
85
  collection do
83
- controller_class.extra_actions.each do |action, methods|
86
+ actions = controller_class.extra_actions
87
+ actions = actions.select { |k,v| controller_class.method_defined?(k) } if skip_undefined
88
+ actions.each do |action, methods|
84
89
  methods = [methods] if methods.is_a?(Symbol) || methods.is_a?(String)
85
90
  methods.each do |m|
86
91
  public_send(m, action)
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.0
4
+ version: 0.0.1
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: 2020-09-16 00:00:00.000000000 Z
11
+ date: 2020-09-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails