cathode 0.0.1
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 +7 -0
- data/LICENSE +20 -0
- data/README.md +236 -0
- data/Rakefile +26 -0
- data/app/assets/javascripts/cathode/application.js +13 -0
- data/app/assets/stylesheets/cathode/application.css +13 -0
- data/app/controllers/cathode/base_controller.rb +47 -0
- data/app/helpers/cathode/application_helper.rb +4 -0
- data/app/views/layouts/cathode/application.html.erb +14 -0
- data/config/routes.rb +2 -0
- data/lib/cathode.rb +14 -0
- data/lib/cathode/_version.rb +3 -0
- data/lib/cathode/action.rb +82 -0
- data/lib/cathode/base.rb +28 -0
- data/lib/cathode/engine.rb +5 -0
- data/lib/cathode/exceptions.rb +3 -0
- data/lib/cathode/request.rb +15 -0
- data/lib/cathode/resource.rb +40 -0
- data/lib/cathode/version.rb +49 -0
- data/lib/tasks/cathode_tasks.rake +4 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/api/dummy_api.rb +4 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/models/product.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +28 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +29 -0
- data/spec/dummy/config/environments/production.rb +80 -0
- data/spec/dummy/config/environments/test.rb +36 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +12 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20140404222551_create_products.rb +10 -0
- data/spec/dummy/db/schema.rb +23 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +312 -0
- data/spec/dummy/log/test.log +12708 -0
- data/spec/dummy/public/404.html +58 -0
- data/spec/dummy/public/422.html +58 -0
- data/spec/dummy/public/500.html +57 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/spec/factories/products.rb +8 -0
- data/spec/integration/api_spec.rb +88 -0
- data/spec/lib/action_spec.rb +140 -0
- data/spec/lib/base_spec.rb +28 -0
- data/spec/lib/request_spec.rb +5 -0
- data/spec/lib/resources_spec.rb +78 -0
- data/spec/lib/versioning_spec.rb +104 -0
- data/spec/spec_helper.rb +30 -0
- data/spec/support/factories/products.rb +3 -0
- data/spec/support/helpers.rb +9 -0
- metadata +259 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4d84a893f57e8bb3db9121ed7c77b5129b097332
|
4
|
+
data.tar.gz: 0ac0b4a4164c8eff2324e3dc394b220110f1d7dc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8595c76223683aa134f22aeb9498569706ac4059f2b738e1420cb0603533aaae5327c93ee1ccfc7a2ee27b66dfde1323e38509da7de3c8a75d8976bea16e1455
|
7
|
+
data.tar.gz: 1bd851d2603db7b9c0ab5e0d07e2f64620c10cd52b48212e714fa9b99082d1ab9900e29666d2692f6cd855bed2880b95e8aa0a246529306865e21b276bcfea60
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2014 Moby, Inc.
|
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,236 @@
|
|
1
|
+
**This gem is under heavy development and is not ready to be used in product
|
2
|
+
systems.**
|
3
|
+
|
4
|
+
# Cathode
|
5
|
+
Cathode is a gem for Rails projects that generates API boilerplate for REST
|
6
|
+
applications.
|
7
|
+
|
8
|
+
## Features
|
9
|
+
* Automatically generate endpoints (routes + controllers) for common RESTful
|
10
|
+
actions:
|
11
|
+
* Listing resources, optionally filtered and paginated
|
12
|
+
* Finding a single resource
|
13
|
+
* Creating a new resource
|
14
|
+
* Updating a resource
|
15
|
+
* Deleting a resource
|
16
|
+
* Endpoints respond to JSON and output JSON by default (possibly add XML et al later on?)
|
17
|
+
* Versioning of endpoints
|
18
|
+
* Deprecation
|
19
|
+
* Auto-documentation
|
20
|
+
|
21
|
+
## Getting Started
|
22
|
+
To generate the `api` directory and mount the engine:
|
23
|
+
```ruby
|
24
|
+
rails generate cool
|
25
|
+
```
|
26
|
+
|
27
|
+
*Note: Your API can be defined using the `resource` method in your `api/api.rb` file,
|
28
|
+
using separate files and the `Cathode::API` class, or a combination of both. For
|
29
|
+
brevity, this document uses `resource` with the assumption that everything is in
|
30
|
+
`api.rb`. See the section below, “Files & Naming Conventions,” for details on
|
31
|
+
using the other method.*
|
32
|
+
|
33
|
+
In the simplest case, you can use only default actions:
|
34
|
+
```ruby
|
35
|
+
resource :products, actions: [:index, :show, :search]
|
36
|
+
```
|
37
|
+
|
38
|
+
Contrary to Rails’s `routes.rb` file–in which the default actions are included
|
39
|
+
unless explicitly excluded–only actions that you specify are defined. Out of
|
40
|
+
the box, the actions available are: `:index, :show, :create, :update, :delete, :search`.
|
41
|
+
|
42
|
+
In this case, the following routes are created: `get api/products/`, `get
|
43
|
+
api/products/{id}`, and `get api/products/search`. By default, all products will
|
44
|
+
be returned in the `index` call, and no permissions will be enforced on the
|
45
|
+
`show` call. By default, the `search` call will take a `query` parameter and
|
46
|
+
search for it using the `Product.title` field.
|
47
|
+
|
48
|
+
## Serialization
|
49
|
+
Cathode doesn’t do any explicit serialization of resources when responding to
|
50
|
+
requests. However, it does use `render: json`, which will invoke [ActiveModel
|
51
|
+
serializers](https://github.com/rails-api/active_model_serializers) if you’ve
|
52
|
+
defined them.
|
53
|
+
|
54
|
+
## Versioning
|
55
|
+
Versioning is encouraged to prevent you from introducing breaking API changes.
|
56
|
+
Your API’s versions should use [Semantic Versioning](http://semver.org/), which
|
57
|
+
enables Cathode to deduce patches, non-breaking changes, and breaking changes. Cathode
|
58
|
+
also makes it easy to deprecate all or part of any version of your API at any
|
59
|
+
time.
|
60
|
+
|
61
|
+
If you define your resources without any versions, Cathode assumes it’s version
|
62
|
+
`1.0.0` of your API. When you’re ready to introduce changes, you can
|
63
|
+
easily provision a new version:
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
resource :products, actions: [:index, :show, :search]
|
67
|
+
|
68
|
+
version 1.1 do
|
69
|
+
resource :sales, actions: [:all]
|
70
|
+
# the products resource is inherited from version 1
|
71
|
+
end
|
72
|
+
|
73
|
+
version 2 do
|
74
|
+
# the products resource is inherited from version 1.1, except we explicitly
|
75
|
+
# remove the `search` action
|
76
|
+
resource :products
|
77
|
+
remove_action :search
|
78
|
+
end
|
79
|
+
end
|
80
|
+
```
|
81
|
+
|
82
|
+
Versions inherit from their ancestors, so anything not explicitly changed in
|
83
|
+
version `2` will be carried over from version `1.1`, which in turn inherits from
|
84
|
+
version `1`.
|
85
|
+
|
86
|
+
In version `1.1`, we’ve added a new `sales` endpoint. This doesn’t introduce a
|
87
|
+
breaking change, as users of version `1.0` can still use it without knowing
|
88
|
+
about the `sales` endpoint.
|
89
|
+
|
90
|
+
However, in version `2` we *do* introduce a breaking change–namely, that
|
91
|
+
products can no longer be searched. Users of versions `1.x` of our API will
|
92
|
+
still be able to access the endpoint, but users of version `2` will not.
|
93
|
+
|
94
|
+
Usually, changes like these would require the addition of new route namespaces
|
95
|
+
and groups of controllers. With Cathode, these are all taken care of for you.
|
96
|
+
|
97
|
+
## Goodies on the `index` action
|
98
|
+
By default `index` actions return all records in your resource’s default scope.
|
99
|
+
However, common operations–like filtering, sorting, pagination, cursoring,
|
100
|
+
etc–are also supported. For example, an application might make the following API
|
101
|
+
call:
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
GET /api/products?query=flashlight&sort=desc&page=5
|
105
|
+
```
|
106
|
+
|
107
|
+
To add support for this functionality in Cathode, just flip on querying, sorting,
|
108
|
+
and paging in the `index` action:
|
109
|
+
|
110
|
+
```ruby
|
111
|
+
resource :products do
|
112
|
+
action :index do
|
113
|
+
allows :querying, :sorting, :paging
|
114
|
+
end
|
115
|
+
end
|
116
|
+
```
|
117
|
+
|
118
|
+
## Params
|
119
|
+
All actions have access to the request `params` hash.
|
120
|
+
|
121
|
+
## Custom action behavior
|
122
|
+
Of course, you won’t want to use Cathode’s default actions in every scenario.
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
version 2.1 do
|
126
|
+
resource :sales, actions: [:all] do
|
127
|
+
action :show do
|
128
|
+
change 'Checks user permission'
|
129
|
+
access_filter do |current_user|
|
130
|
+
resource.user == current_user
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
```
|
136
|
+
|
137
|
+
In this case, we need to prevent users from seeing sales that aren’t theirs.
|
138
|
+
Happily, Cathode provides some neat shorthands for common scenarios like this.
|
139
|
+
`access_filter` can be applied to any action, and should be a method that
|
140
|
+
returns `true` if the user can access the resource and `false` if not. If the
|
141
|
+
user cannot access the resource, a `401 Unauthorized` header will be sent.
|
142
|
+
|
143
|
+
In those cases where you want to do all of the logic yourself, and just want the
|
144
|
+
endpoints that Cathode generates, you can override an action entirely:
|
145
|
+
|
146
|
+
```ruby
|
147
|
+
resource :sales, actions: [:all] do
|
148
|
+
# show a random sale instead
|
149
|
+
override_action :show do
|
150
|
+
render json: Sale.sample
|
151
|
+
end
|
152
|
+
end
|
153
|
+
```
|
154
|
+
|
155
|
+
## Deprecation
|
156
|
+
With Cathode’s slick versioning, you’ll be implicitly deprecating junk in previous
|
157
|
+
versions each time you introduce a new breaking change. When that happens, users
|
158
|
+
of previous versions of your API should be told that a feature they’re using is
|
159
|
+
deprecated. By default, Cathode will respond with a deprecation warning for those
|
160
|
+
users. So users of version `1.1` of your API would receive the following
|
161
|
+
response when making a call to `/api/products/search`:
|
162
|
+
|
163
|
+
```json
|
164
|
+
{
|
165
|
+
"products": [ array of the products found… ]
|
166
|
+
"messages": [
|
167
|
+
"The search endpoint is deprecated and is removed in version 2.0.0 of the
|
168
|
+
API"]
|
169
|
+
}
|
170
|
+
```
|
171
|
+
|
172
|
+
## Files & Naming Conventions
|
173
|
+
While this example has been putting all actions in a single file, in reality
|
174
|
+
you’ll probably want to specify individual files for each resource. You can use
|
175
|
+
the same versioning scheme in those files; as long as your resource APIs inherit
|
176
|
+
from `Cathode::API`, Cathode will match up everything accordingly:
|
177
|
+
|
178
|
+
```ruby
|
179
|
+
# app/api/products_api.rb
|
180
|
+
|
181
|
+
class ProductsAPI < Cathode::API
|
182
|
+
actions: [:index, :show, :search] # version 1.0.0 is implied
|
183
|
+
|
184
|
+
version 2 do
|
185
|
+
remove_action :search
|
186
|
+
end
|
187
|
+
end
|
188
|
+
```
|
189
|
+
|
190
|
+
Since nothing about products changed in version 1.2 (which only added sales,
|
191
|
+
above), it will use the same actions as it did in version 1. In version 2,
|
192
|
+
everything is carried over except for the `search` endpoint.
|
193
|
+
|
194
|
+
## Documentation & Changelogs
|
195
|
+
By sticking to Cathode’s versioning scheme, you tell it a lot about your API. So
|
196
|
+
much, in fact, that we can use it to automatically generate documentation for
|
197
|
+
all versions of your API and generate a changelog. Running `cool docs` will
|
198
|
+
generate the documentation at `docs/api/1.0.0`, `docs/api/1.1.0`,
|
199
|
+
`docs/api/2.0.0`, and `docs/api/2.1.0`. It will also automatically add a
|
200
|
+
`Changelog`:
|
201
|
+
|
202
|
+
```markdown
|
203
|
+
# Changelog
|
204
|
+
## Version 2.1.0
|
205
|
+
Checks user permission in `sales#show`.
|
206
|
+
|
207
|
+
## Version 2.0.0
|
208
|
+
Removes the `search` endpoint from `products` resource.
|
209
|
+
|
210
|
+
## Version 1.1.0
|
211
|
+
Adds `sales` resource with the following endpoints:
|
212
|
+
- `GET /api/sales`
|
213
|
+
- `GET /api/sales/{id}`
|
214
|
+
- `GET /api/sales/search`
|
215
|
+
- `POST /api/sales`
|
216
|
+
- `PUT /api/sales/{id}`
|
217
|
+
- `DELETE /api/sales/{id}`
|
218
|
+
|
219
|
+
## Version 1.0.0
|
220
|
+
Initial release
|
221
|
+
|
222
|
+
Adds `products` resource with the following endpoints:
|
223
|
+
- `GET /api/products`
|
224
|
+
- `GET /api/products/{id}`
|
225
|
+
- `GET /api/products/search`
|
226
|
+
- `POST /api/products`
|
227
|
+
- `PUT /api/products/{id}`
|
228
|
+
- `DELETE /api/products/{id}`
|
229
|
+
```
|
230
|
+
|
231
|
+
## Related Reading & Projects
|
232
|
+
* [Versionist](https://github.com/bploetz/versionist)
|
233
|
+
* [Existing Rails API Solutions Suck](http://joshsymonds.com/blog/2013/02/22/existing-rails-api-solutions-suck/])
|
234
|
+
* [Grape](https://github.com/intridea/grape)
|
235
|
+
* [Roar](https://github.com/apotonick/roar)
|
236
|
+
* [Rails API](https://github.com/rails-api/rails-api)
|
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
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 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'Cathode'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.rdoc')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
|
18
|
+
load 'rails/tasks/engine.rake'
|
19
|
+
|
20
|
+
Bundler::GemHelper.install_tasks
|
21
|
+
|
22
|
+
require 'rspec/core'
|
23
|
+
require 'rspec/core/rake_task'
|
24
|
+
desc "Run all specs in spec directory (excluding plugin specs)"
|
25
|
+
RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare')
|
26
|
+
task :default => :spec
|
@@ -0,0 +1,13 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
+
// listed below.
|
3
|
+
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
+
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
|
6
|
+
//
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
+
// compiled file.
|
9
|
+
//
|
10
|
+
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
|
11
|
+
// about supported directives.
|
12
|
+
//
|
13
|
+
//= require_tree .
|
@@ -0,0 +1,13 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the top of the
|
9
|
+
* compiled file, but it's generally better to create a new file per style scope.
|
10
|
+
*
|
11
|
+
*= require_self
|
12
|
+
*= require_tree .
|
13
|
+
*/
|
@@ -0,0 +1,47 @@
|
|
1
|
+
class Cathode::BaseController < ActionController::Base
|
2
|
+
before_action :process_access_filter
|
3
|
+
|
4
|
+
def index
|
5
|
+
render json: resources.load
|
6
|
+
end
|
7
|
+
|
8
|
+
def create
|
9
|
+
render json: model.create(resource_params)
|
10
|
+
end
|
11
|
+
|
12
|
+
def destroy
|
13
|
+
resource.destroy
|
14
|
+
head :ok
|
15
|
+
end
|
16
|
+
|
17
|
+
def show
|
18
|
+
make_request(request)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def make_request(http_request)
|
24
|
+
request = Cathode::Request.new(http_request, params)
|
25
|
+
render json: request.body, status: request.status
|
26
|
+
end
|
27
|
+
|
28
|
+
def resources
|
29
|
+
model.all
|
30
|
+
end
|
31
|
+
|
32
|
+
def resource
|
33
|
+
model.find params[:id]
|
34
|
+
end
|
35
|
+
|
36
|
+
def resource_params
|
37
|
+
params[controller_name.singularize]
|
38
|
+
end
|
39
|
+
|
40
|
+
def model
|
41
|
+
controller_name.classify.constantize
|
42
|
+
end
|
43
|
+
|
44
|
+
def process_access_filter
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Cathode</title>
|
5
|
+
<%= stylesheet_link_tag "cathode/application", media: "all" %>
|
6
|
+
<%= javascript_include_tag "cathode/application" %>
|
7
|
+
<%= csrf_meta_tags %>
|
8
|
+
</head>
|
9
|
+
<body>
|
10
|
+
|
11
|
+
<%= yield %>
|
12
|
+
|
13
|
+
</body>
|
14
|
+
</html>
|
data/config/routes.rb
ADDED
data/lib/cathode.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'cathode/engine'
|
2
|
+
require 'cathode/base'
|
3
|
+
require 'cathode/exceptions'
|
4
|
+
|
5
|
+
module Cathode
|
6
|
+
class Engine < ::Rails::Engine
|
7
|
+
config.generators do |g|
|
8
|
+
g.test_framework :rspec, :fixture => false
|
9
|
+
g.fixture_replacement :factory_girl, :dir => 'spec/factories'
|
10
|
+
g.assets false
|
11
|
+
g.helper false
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Cathode
|
2
|
+
class Action
|
3
|
+
attr_reader :action_access_filter,
|
4
|
+
:name,
|
5
|
+
:resource
|
6
|
+
|
7
|
+
|
8
|
+
def self.create(action, resource, &block)
|
9
|
+
klass = case action
|
10
|
+
when :index
|
11
|
+
IndexAction
|
12
|
+
when :show
|
13
|
+
ShowAction
|
14
|
+
when :create
|
15
|
+
CreateAction
|
16
|
+
when :update
|
17
|
+
UpdateAction
|
18
|
+
when :destroy
|
19
|
+
DestroyAction
|
20
|
+
end
|
21
|
+
klass.new(action, resource, &block)
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(action, resource, &block)
|
25
|
+
@name, @resource = action, resource
|
26
|
+
|
27
|
+
self.instance_eval &block if block_given?
|
28
|
+
end
|
29
|
+
|
30
|
+
def perform(params)
|
31
|
+
if action_access_filter && !action_access_filter.call
|
32
|
+
return { status: :unauthorized }
|
33
|
+
end
|
34
|
+
|
35
|
+
body = perform_action params
|
36
|
+
|
37
|
+
return { body: body, status: :ok }
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def model
|
43
|
+
resource.to_s.camelize.singularize.constantize
|
44
|
+
end
|
45
|
+
|
46
|
+
def access_filter(&filter)
|
47
|
+
@action_access_filter = filter
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class IndexAction < Action
|
52
|
+
def perform_action(params)
|
53
|
+
model.all
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class ShowAction < Action
|
58
|
+
def perform_action(params)
|
59
|
+
model.find params[:id]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class CreateAction < Action
|
64
|
+
def perform_action(params)
|
65
|
+
model.create params
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class UpdateAction < Action
|
70
|
+
def perform_action(params)
|
71
|
+
record = model.find(params[:id])
|
72
|
+
record.update params
|
73
|
+
record.reload
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class DestroyAction < Action
|
78
|
+
def perform_action(params)
|
79
|
+
model.find(params[:id]).destroy
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|