caprese 0.2.0 → 0.2.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 +4 -4
- data/README.md +475 -3
- data/lib/caprese.rb +4 -3
- data/lib/caprese/controller/concerns/query.rb +3 -5
- data/lib/caprese/error.rb +6 -2
- data/lib/caprese/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6fa772365d2becc2bae5be4328595931ffee6107
|
4
|
+
data.tar.gz: 9d2aee61283a8abd50d736b48bd255ab73e5f0b8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d23e29b6a9f9f5933350566da1f199c15cb4537320d235a11377147154b80dc9a789b658b59b43ef88a264a97f65bf1a7a0631f2962b1e71c813339887423459
|
7
|
+
data.tar.gz: 70b9ba12711fcdf36b4d9834a11d5bfc2cb763855d2e5115bf2f94c920085cb52bbf306e62a5ad8e38dac114eb0b51dd8e20e380f050c6607a7379bb1cf871af
|
data/README.md
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# Caprese
|
2
2
|
|
3
3
|
Caprese is a Rails library for creating RESTful APIs in as few words as possible. It handles all CRUD operations on resources and their associations for you, and you can customize how these operations
|
4
|
-
are carried out
|
4
|
+
are carried out, allowing for infinite possibilities while focusing on work that matters to you, instead of writing repetitive code for each action of each resource in your application.
|
5
5
|
|
6
|
-
|
6
|
+
For now, the only format that is supported by Caprese is the [JSON API schema](http://jsonapi.org/format/). In the future, Caprese will support a more straightforward (but less powerful) JSON format as well, for simpler use cases.
|
7
7
|
|
8
8
|
## Installation
|
9
9
|
|
@@ -21,9 +21,481 @@ Or install it yourself as:
|
|
21
21
|
|
22
22
|
$ gem install caprese
|
23
23
|
|
24
|
+
## Philosophy
|
25
|
+
|
26
|
+
Caprese provides a controller framework that can automatically carry out `index`, `show`, `create`, `update`, and `destroy` actions for you with as little configuration as possible. You could write these methods yourself for every resource in your application, but the thing is, these 5 actions essentially do the same three things:
|
27
|
+
|
28
|
+
1. Find a resource or set of resources, based on the parameters provided
|
29
|
+
2. Optionally apply a number of changes to them, based on the data provided and the action selected
|
30
|
+
3. Serialize and respond with the resource(s), in the format that was requested
|
31
|
+
|
32
|
+
Caprese does all of this dirty work for you, so all you have to do is customize its behavior to fine-tune the results. You customize the behavior by creating resource representations using serializers, by overriding intermediate helper methods, and by defining any number of callbacks in and around the actions to fully control each step of the process outlined above.
|
33
|
+
|
34
|
+
There are four components to creating an API using Caprese: controllers, routes, serializers, and records.
|
35
|
+
|
36
|
+
Before reading any further, we recommend that you read the [JSON API schema](http://jsonapi.org/format/) in full. It covers a lot of important information on all three steps above: modifying resource sets through query parameters, making changes to resources, modifying the response format, and more. Rather than make this doc a deep JSON API tutorial, we are going to assume you have read the schema and know what we're talking about.
|
37
|
+
|
24
38
|
## Usage
|
25
39
|
|
26
|
-
|
40
|
+
### Set up your controller structure
|
41
|
+
|
42
|
+
You are familiar with using `ApplicationController` and having your controllers inherit from it. In Caprese, your `ApplicationController` is a `Caprese::Controller`, and everything inherits from it:
|
43
|
+
|
44
|
+
```
|
45
|
+
# app/controllers/api/application_controller.rb
|
46
|
+
module API
|
47
|
+
class ApplicationController < Caprese::Controller
|
48
|
+
# Global API configuration
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# app/controllers/api/v1/application_controller.rb
|
53
|
+
module API
|
54
|
+
module V1
|
55
|
+
class ApplicationController < API::ApplicationController
|
56
|
+
# API V1 configuration
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
```
|
61
|
+
|
62
|
+
This structure allows you to define global API configuration, as well as versioned configuration specific to your `API::V1`.
|
63
|
+
|
64
|
+
### Defining endpoints for a resource
|
65
|
+
|
66
|
+
Let's say you have a model `Product`. You'd create a versioned controller for it, inheriting from your `API::V1::ApplicationController`:
|
67
|
+
|
68
|
+
```
|
69
|
+
# app/controllers/api/v1/products_controller.rb
|
70
|
+
module API
|
71
|
+
module V1
|
72
|
+
class ProductsController < ApplicationController
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
```
|
77
|
+
|
78
|
+
You should also create a `Serializer` for `Product`, so Caprese will know what attributes to render in the response to requests.
|
79
|
+
|
80
|
+
Defining your serializers is simple:
|
81
|
+
|
82
|
+
```
|
83
|
+
# app/serializers/api/v1/application_serializer.rb
|
84
|
+
module API
|
85
|
+
module V1
|
86
|
+
class ApplicationSerializer < Caprese::Serializer
|
87
|
+
# API::V1 serializer configuration
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# app/serializers/api/v1/product_serializer.rb
|
93
|
+
module API
|
94
|
+
module V1
|
95
|
+
class ProductSerializer < ApplicationSerializer
|
96
|
+
attributes :title, :description
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
```
|
101
|
+
|
102
|
+
This tells Caprese that when rendering requests for products, it should only include the `product.title` and `product.description` in the response.
|
103
|
+
|
104
|
+
`Caprese::Serializer` inherits from `ActiveModel::Serializer`, thus leaving the functionality of serializers to be defined by [ActiveModelSerializers](https://github.com/rails-api/active_model_serializers), a powerful library in Rails API. `Caprese::Serializer` automatically creates `links` for both the resource itself, and *all* of the resource's relationships.
|
105
|
+
|
106
|
+
From there, add a route:
|
107
|
+
|
108
|
+
```
|
109
|
+
# config/routes.rb
|
110
|
+
Rails.application.routes.draw do
|
111
|
+
namespace 'api' do
|
112
|
+
namespace 'v1' do
|
113
|
+
caprese_resources :products
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
```
|
118
|
+
|
119
|
+
With just that, you've just created fully functioning endpoints for `index`, `show`, and `destroy`:
|
120
|
+
|
121
|
+
```
|
122
|
+
GET /api/v1/products
|
123
|
+
GET /api/v1/products/:id
|
124
|
+
DELETE /api/v1/products/:id
|
125
|
+
```
|
126
|
+
|
127
|
+
Make a request to any of these endpoints, and your response will be product(s) with their `title` and `description`.
|
128
|
+
|
129
|
+
You can also modify the requests using JSON API query parameters like `filter`, `sort`, `page`, `limit`, `offset`, `fields`, and `includes`.
|
130
|
+
|
131
|
+
You might ask: What about `create` and `update`? Well, those require some configuration in order to work:
|
132
|
+
|
133
|
+
```
|
134
|
+
# app/controllers/api/v1/products_controller.rb
|
135
|
+
module API
|
136
|
+
module V1
|
137
|
+
class ProductsController < ApplicationController
|
138
|
+
|
139
|
+
def permitted_create_params
|
140
|
+
[:title, :description]
|
141
|
+
end
|
142
|
+
|
143
|
+
def permitted_update_params
|
144
|
+
[:description]
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
```
|
151
|
+
|
152
|
+
With that, you've stated that when creating a product, the params that are permitted to be assigned to the new product are `title` and `description`. When updating a product, the params that are permitted to be updated are nothing but `description`. You can't update the `title`.
|
153
|
+
|
154
|
+
That's it. You now have five fully functioning endpoints:
|
155
|
+
|
156
|
+
```
|
157
|
+
GET /api/v1/products
|
158
|
+
GET /api/v1/products/:id
|
159
|
+
POST /api/v1/products
|
160
|
+
PATCH/PUT /api/v1/products/:id
|
161
|
+
DELETE /api/v1/products/:id
|
162
|
+
```
|
163
|
+
|
164
|
+
### Managing relationships of resources
|
165
|
+
|
166
|
+
The above is a little misleading. After doing the steps above, you'll actually end up with EIGHT endpoints:
|
167
|
+
|
168
|
+
```
|
169
|
+
GET /api/v1/products
|
170
|
+
GET /api/v1/products/:id
|
171
|
+
POST /api/v1/products
|
172
|
+
PATCH/PUT /api/v1/products/:id
|
173
|
+
DELETE /api/v1/products/:id
|
174
|
+
GET /api/v1/products/:id/:relationship
|
175
|
+
GET /api/v1/products/:id/relationships/:relationship
|
176
|
+
PATCH/PUT/DELETE /api/v1/products/:id/relationships/:relationship
|
177
|
+
```
|
178
|
+
|
179
|
+
The three new endpoints are for reading and managing relationships (known as `associations` in Rails) of the resource.
|
180
|
+
|
181
|
+
You can also specify which relationships can be assigned to a resource when created or which relationships can be updated:
|
182
|
+
|
183
|
+
```
|
184
|
+
def permitted_create_params
|
185
|
+
[:title, :description]
|
186
|
+
end
|
187
|
+
|
188
|
+
def permitted_update_params
|
189
|
+
[:description, :orders]
|
190
|
+
end
|
191
|
+
```
|
192
|
+
|
193
|
+
You could thus update the orders of a product in by making a call to one of two endpoints:
|
194
|
+
```
|
195
|
+
PATCH/PUT /api/v1/products/:id # include `orders` in `relationships` member
|
196
|
+
PATCH/POST/DELETE /api/v1/products/:id/relationships/orders # provide resource identifiers for orders
|
197
|
+
```
|
198
|
+
|
199
|
+
### Scoping resources to customize behavior
|
200
|
+
|
201
|
+
Let's say you don't want a user to be able to request all the products in your database, you only want them to be able to request the ones that belong to them. If you determined `current_user` based on the authentication credentials they used, you could scope your products to only `current_user` by overriding the intermediate helper method `record_scope`:
|
202
|
+
|
203
|
+
```
|
204
|
+
# app/controllers/api/v1/products_controller.rb
|
205
|
+
module API
|
206
|
+
module V1
|
207
|
+
class ProductsController < ApplicationController
|
208
|
+
def record_scope(type)
|
209
|
+
case type
|
210
|
+
when :products
|
211
|
+
Product.where(user: current_user)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
```
|
218
|
+
|
219
|
+
Let's take that one step further and state that when that user updates the orders of an existing product, you only want them to be able to add orders that belong to them, too. Simple:
|
220
|
+
|
221
|
+
```
|
222
|
+
def record_scope(type)
|
223
|
+
case type
|
224
|
+
when :products
|
225
|
+
Product.where(user: current_user)
|
226
|
+
when :orders
|
227
|
+
Order.where(user: current_user)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
```
|
231
|
+
|
232
|
+
Now, if they were to make a request like `POST /api/v1/products/1/relationships/orders` to append an order to one of their products, and they submit a resource identifier for an order that did not belong to them, the response would be `404 Not Found`.
|
233
|
+
|
234
|
+
There is one more consideration to be made here. What if, when this user makes a request to `GET /api/v1/products/1/orders` to get the list of orders for one of their products, you only want to return orders that have been created in the last week. This time, you override another intermediate helper method, `relationship_scope`:
|
235
|
+
|
236
|
+
```
|
237
|
+
def relationship_scope(name, scope)
|
238
|
+
case name
|
239
|
+
when :orders
|
240
|
+
scope.where('created_at < ?', 1.week.ago)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
```
|
244
|
+
|
245
|
+
`name` is the name of the relationship to scope, and `scope` is the existing scope for the relationship, in this case, equal to `Product.find(1).orders`.
|
246
|
+
|
247
|
+
### Modifying control flow with callbacks
|
248
|
+
|
249
|
+
You may want to customize the behavior of an action, but you don't want to go about the task of overriding it entirely. Caprese defines a number of callbacks to modify the control flow for any action, allowing you to keep controller logic where it belongs.
|
250
|
+
|
251
|
+
```
|
252
|
+
# app/controllers/api/v1/orders_controller.rb
|
253
|
+
module API
|
254
|
+
module V1
|
255
|
+
class OrdersController < ApplicationController
|
256
|
+
after_initialize :calculate_price_from_line_items, :do_something_else
|
257
|
+
after_create :send_confirmation_email
|
258
|
+
|
259
|
+
private
|
260
|
+
|
261
|
+
# If `Order#line_items` is a has_many association, and is created with an order (see: nested association creation),
|
262
|
+
# iterate over each line item and sum its price to determine the total order price
|
263
|
+
def calculate_price_from_line_items(order)
|
264
|
+
if order.line_items.any?
|
265
|
+
order.price = order.line_items.inject(0) do |sum, li|
|
266
|
+
sum += li.price
|
267
|
+
end
|
268
|
+
else
|
269
|
+
order.errors.add(:line_items, :blank) # an order must have line items
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
# After creating an order, send the customer a confirmation email
|
274
|
+
def send_confirmation_email(order)
|
275
|
+
ConfirmationMailer.send(order)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
```
|
281
|
+
|
282
|
+
The following callbacks are defined by Caprese:
|
283
|
+
|
284
|
+
```
|
285
|
+
before_query (called before anything)
|
286
|
+
after_query (called after the response is rendered)
|
287
|
+
after_initialize (called in #create after the resource is instantiated)
|
288
|
+
before_create (alias for after_initialize)
|
289
|
+
after_create (rest are self explanatory)
|
290
|
+
before_update
|
291
|
+
after_update
|
292
|
+
before_save
|
293
|
+
after_save
|
294
|
+
before_destroy
|
295
|
+
after_destroy
|
296
|
+
```
|
297
|
+
|
298
|
+
Reading this, note that saying `before_action :do_something, only: [:create]` is not the same as saying `before_create :do_something`. But you can use the former if you like, to customize further.
|
299
|
+
|
300
|
+
### Creating nested associations
|
301
|
+
|
302
|
+
You can also use Caprese to created nested associations when creating their owners. For example, if I have two models:
|
303
|
+
|
304
|
+
```
|
305
|
+
class Order < ActiveRecord::Base
|
306
|
+
has_many :line_items, autosave: true
|
307
|
+
end
|
308
|
+
|
309
|
+
class LineItem < ActiveRecord::Base
|
310
|
+
belongs_to :order
|
311
|
+
end
|
312
|
+
```
|
313
|
+
|
314
|
+
I can send a resource document to `POST /api/v1/orders` that looks like this:
|
315
|
+
|
316
|
+
```json
|
317
|
+
{
|
318
|
+
"data": {
|
319
|
+
"type": "orders",
|
320
|
+
"attributes": {
|
321
|
+
"some_order_attribute": "..."
|
322
|
+
},
|
323
|
+
"relationships": {
|
324
|
+
"line_items": {
|
325
|
+
"data": [
|
326
|
+
{
|
327
|
+
"type": "line_items",
|
328
|
+
"attributes": {
|
329
|
+
"price": 5.0
|
330
|
+
}
|
331
|
+
},
|
332
|
+
{
|
333
|
+
"type": "line_items",
|
334
|
+
"attributes": {
|
335
|
+
"price": 6.0
|
336
|
+
}
|
337
|
+
}
|
338
|
+
]
|
339
|
+
}
|
340
|
+
}
|
341
|
+
}
|
342
|
+
}
|
343
|
+
```
|
344
|
+
|
345
|
+
and once I configure my controller to indicate that it is permitted to create line items with orders, it will work:
|
346
|
+
|
347
|
+
```
|
348
|
+
# app/controllers/api/v1/orders_controller.rb
|
349
|
+
module API
|
350
|
+
module V1
|
351
|
+
class OrdersController < ApplicationController
|
352
|
+
def permitted_create_params
|
353
|
+
[:some_order_attribute, line_items: [:price]]
|
354
|
+
end
|
355
|
+
end
|
356
|
+
end
|
357
|
+
end
|
358
|
+
```
|
359
|
+
|
360
|
+
You could apply the same logic to `permitted_update_params` to update line items through `PATCH /api/v1/orders/:id`, just add an `"id"` field to the relationship data of each line item so Caprese knows which one to update.
|
361
|
+
|
362
|
+
### Handling errors
|
363
|
+
|
364
|
+
Errors in Caprese come in two forms: model errors, and controller errors.
|
365
|
+
|
366
|
+
#### Model Errors
|
367
|
+
|
368
|
+
Model errors are returned from the server looking like this:
|
369
|
+
|
370
|
+
```json
|
371
|
+
{
|
372
|
+
"errors": [
|
373
|
+
{
|
374
|
+
"source": { "pointer": "/data/attributes/price" },
|
375
|
+
"code": "blank",
|
376
|
+
"detail": "Price cannot be blank."
|
377
|
+
},
|
378
|
+
{
|
379
|
+
"source": { "pointer": "/data/relationships/line_items" },
|
380
|
+
"code": "blank",
|
381
|
+
"detail": "Line items cannot be blank."
|
382
|
+
},
|
383
|
+
{
|
384
|
+
"source": { "pointer": "/data/relationships/line_items/data/attributes/price" },
|
385
|
+
"code": "blank",
|
386
|
+
"detail": "Price cannot be blank."
|
387
|
+
}
|
388
|
+
]
|
389
|
+
}
|
390
|
+
```
|
391
|
+
|
392
|
+
Model errors have the same interface as in ActiveRecord, but with some added functionality on top. ActiveRecord errors only contain a message (for example: `price: 'Price cannot be blank'`). Caprese model errors also have a code (for example: `price: { code: :blank, message: 'Price cannot be blank.' }`), which is a much more programmatic solution. Rails 5 fixes this, but since Caprese supports both Rails 4 and Rails 5, we defined our own functionality for the time being.
|
393
|
+
|
394
|
+
To make use of Caprese model errors, add the `Caprese::Record` concern to your models:
|
395
|
+
|
396
|
+
```
|
397
|
+
class Product < ActiveRecord::Base
|
398
|
+
include Caprese::Record
|
399
|
+
end
|
400
|
+
```
|
401
|
+
|
402
|
+
The other thing that `Caprese::Record` brings to the table is that it allows you to create separate translations for error messages depending on the context: API, or application. Application is what you're used to. You can define a translation like `en.active_record.errors.models.product.attributes.title.blank = 'Hey buddy, a product title can't be blank!'` and that user-friendly error message is what will show up in your application. But using the same user-friendly error message to a third party API developer is kinda weird.
|
403
|
+
|
404
|
+
You can define your own set of translations specifically for your API: `en.api.v1.errors.models.product.title.blank = 'Custom error message'`. This requires some configuration on your part. You have to tell Caprese where to look by setting `Caprese.config.i18n_scope = 'api.v1.errors'`
|
405
|
+
|
406
|
+
Caprese looks for translations in the following order, and if none of them are defined, it will use `code.to_s` as the error message:
|
407
|
+
|
408
|
+
```
|
409
|
+
# for field errors (attribute or relationship)
|
410
|
+
api.v1.errors.models.[model_name].[field].[code]
|
411
|
+
api.v1.errors.field.[code]
|
412
|
+
api.v1.errors.[code]
|
413
|
+
|
414
|
+
# for errors on base
|
415
|
+
api.v1.errors.models.[model_name].[code]
|
416
|
+
api.v1.errors.[code]
|
417
|
+
```
|
418
|
+
|
419
|
+
#### Controller errors
|
420
|
+
|
421
|
+
Controller errors are returned from the server looking like this:
|
422
|
+
|
423
|
+
```json
|
424
|
+
{
|
425
|
+
"errors": [
|
426
|
+
{
|
427
|
+
"source": { "parameter": "filter" },
|
428
|
+
"code": "invalid",
|
429
|
+
"detail": "Filters provided are invalid."
|
430
|
+
}
|
431
|
+
]
|
432
|
+
}
|
433
|
+
```
|
434
|
+
|
435
|
+
Caprese provides a helper method to easily create controller errors that can have their own translation scope. If at any point in your control flow, say in a callback, you want to immediately halt the request and respond with an error message, you can do the following:
|
436
|
+
|
437
|
+
```
|
438
|
+
fail error(
|
439
|
+
field: :filter,
|
440
|
+
code: :invalid,
|
441
|
+
t: { ... } # translation interpolation variables to use in the error message
|
442
|
+
)
|
443
|
+
```
|
444
|
+
|
445
|
+
Caprese will search for controller errors in the following order, and if none of them are defined, it will use `code.to_s` as the error message:
|
446
|
+
|
447
|
+
```
|
448
|
+
api.v1.errors.controllers.[controller].[action].[field].[code]
|
449
|
+
api.v1.errors.controllers.[controller].[action].[code]
|
450
|
+
api.v1.errors.[code]
|
451
|
+
```
|
452
|
+
|
453
|
+
#### Customizing your error and error message
|
454
|
+
|
455
|
+
The raw error object for Caprese is as follows:
|
456
|
+
|
457
|
+
```
|
458
|
+
fail Error.new(
|
459
|
+
model: ..., # model name
|
460
|
+
controller: ..., # only model name || controller && action should be provided, not both
|
461
|
+
action: ...,
|
462
|
+
field: ...,
|
463
|
+
code: :invalid,
|
464
|
+
t: { ... } # translation interpolation variables to use in the error message
|
465
|
+
)
|
466
|
+
```
|
467
|
+
|
468
|
+
Two translation interpolation variables will be provided for you automatically, on top of whatever ones you pass in. Those two are: `%{field}` and `%{field_title}`. If `field == :my_title`, `%{field} == my_title` and `%{field_title} == My Title`
|
469
|
+
|
470
|
+
### Configuration
|
471
|
+
|
472
|
+
As a guide to configuring Caprese, here is the portion of `lib/caprese.rb` that stores the defaults:
|
473
|
+
|
474
|
+
```
|
475
|
+
# Defines the primary key to use when querying records
|
476
|
+
config.resource_primary_key ||= :id
|
477
|
+
|
478
|
+
# Define URL options for use in UrlHelpers
|
479
|
+
config.default_url_options ||= {}
|
480
|
+
|
481
|
+
# If true, relationship data will not be serialized unless it is in `include`, huge performance boost
|
482
|
+
config.optimize_relationships ||= true
|
483
|
+
|
484
|
+
# Defines the translation scope for model and controller errors
|
485
|
+
config.i18n_scope ||= '' # 'api.v1.errors'
|
486
|
+
|
487
|
+
# The default size of any page queried
|
488
|
+
config.default_page_size ||= 10
|
489
|
+
|
490
|
+
# The maximum size of any page queried
|
491
|
+
config.max_page_size ||= 100
|
492
|
+
```
|
493
|
+
|
494
|
+
You should also look into the configuration for [ActiveModelSerializers](https://github.com/rails-api/active_model_serializers/blob/master/docs/general/configuration_options.md) to customize the serializer behavior further.
|
495
|
+
|
496
|
+
### Overriding an action while still using Caprese helpers
|
497
|
+
|
498
|
+
Coming soon... :)
|
27
499
|
|
28
500
|
## Development
|
29
501
|
|
data/lib/caprese.rb
CHANGED
@@ -18,12 +18,13 @@ module Caprese
|
|
18
18
|
# Define URL options for use in UrlHelpers
|
19
19
|
config.default_url_options ||= {}
|
20
20
|
|
21
|
-
# If true, relationship data will not be serialized unless it is in `include`
|
22
|
-
config.optimize_relationships ||= true
|
23
|
-
|
24
21
|
# If true, links will be rendered as `only_path: true`
|
22
|
+
# TODO: Implement this
|
25
23
|
config.only_path_links ||= true
|
26
24
|
|
25
|
+
# If true, relationship data will not be serialized unless it is in `include`
|
26
|
+
config.optimize_relationships ||= true
|
27
|
+
|
27
28
|
# Defines the translation scope for model and controller errors
|
28
29
|
config.i18n_scope ||= '' # 'api.v1.errors'
|
29
30
|
|
@@ -81,12 +81,10 @@ module Caprese
|
|
81
81
|
# @note We use the term scope, because the collection may be all records of that type,
|
82
82
|
# or the records may be scoped further by overriding this method
|
83
83
|
#
|
84
|
-
# @note If no `type` is provided, the type is assumed to be the controller_record_class
|
85
|
-
#
|
86
84
|
# @param [Symbol] type the type to get a record scope for
|
87
85
|
# @return [Relation] the scope of records of type `type`
|
88
|
-
def record_scope(type
|
89
|
-
|
86
|
+
def record_scope(type)
|
87
|
+
record_class(type).all
|
90
88
|
end
|
91
89
|
|
92
90
|
# Gets a record in a scope using a column/value to search by
|
@@ -170,7 +168,7 @@ module Caprese
|
|
170
168
|
# @return [Relation] the record scope of the queried controller
|
171
169
|
def queried_record_scope
|
172
170
|
unless @queried_record_scope
|
173
|
-
scope = record_scope
|
171
|
+
scope = record_scope(unversion(params[:controller]).to_sym)
|
174
172
|
|
175
173
|
if scope.any? && query_params[:filter].try(:any?)
|
176
174
|
if (valid_filters = query_params[:filter].select { |k, _| scope.column_names.include? k }).present?
|
data/lib/caprese/error.rb
CHANGED
@@ -45,8 +45,10 @@ module Caprese
|
|
45
45
|
I18n.t("#{i18n_scope}.models.#{@model}.#{field}.#{code}", t)
|
46
46
|
elsif i18n_set?("#{i18n_scope}.field.#{code}", t)
|
47
47
|
I18n.t("#{i18n_scope}.field.#{code}", t)
|
48
|
-
|
48
|
+
elsif i18n_set? "#{i18n_scope}.#{code}", t
|
49
49
|
I18n.t("#{i18n_scope}.#{code}", t)
|
50
|
+
else
|
51
|
+
code.to_s
|
50
52
|
end
|
51
53
|
else
|
52
54
|
if i18n_set? "#{i18n_scope}.models.#{@model}.#{code}", t
|
@@ -62,8 +64,10 @@ module Caprese
|
|
62
64
|
I18n.t("#{i18n_scope}.controllers.#{@controller}.#{@action}.#{field}.#{code}", t)
|
63
65
|
elsif i18n_set?("#{i18n_scope}.controllers.#{@controller}.#{@action}.#{code}", t)
|
64
66
|
I18n.t("#{i18n_scope}.controllers.#{@controller}.#{@action}.#{code}", t)
|
65
|
-
|
67
|
+
elsif i18n_set? "#{i18n_scope}.#{code}", t
|
66
68
|
I18n.t("#{i18n_scope}.#{code}", t)
|
69
|
+
else
|
70
|
+
code.to_s
|
67
71
|
end
|
68
72
|
elsif field && i18n_set?("#{i18n_scope}.field.#{code}", t)
|
69
73
|
I18n.t("#{i18n_scope}.field.#{code}", t)
|
data/lib/caprese/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: caprese
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Landgrebe
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: exe
|
12
12
|
cert_chain: []
|
13
|
-
date: 2016-09-
|
13
|
+
date: 2016-09-22 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: active_model_serializers
|