You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Singletons: Default collection_name to singleton_name
The problem
---
Active Resource's custom methods are operations outside of the
conventional collection of CRUD actions. For typical collections of
resources, custom methods operate on the collection itself. For example,
consider a custom `refresh` action for a `Product` resource triggered by
`POST` requests: `POST /products/:product_id/refresh`. The route
utilizes a `:product_id` dynamic segment to identify the `Product` in
question, and the path includes `/refresh` to signify the custom method
to perform.
The concept of a "singleton" resource is that there is only one singular
resource, and operations should consistently modify the same resource.
Since the resource is singular in nature, paths *do not* identify that
resource with an ID. For example, consider a singleton `Inventory`
resource that belongs to a `Product`. Its singleton path would be
`/products/:product_id/inventory`.
Prior to this commit, custom methods invoked by both *instances* and
*classes* of singleton resources ignored the "singleton" nature of
route, and use pluralize nouns instead of singular ones.
For example, consider calls to custom "report" and "reset" methods for
an instance of a singleton `Inventory` resource:
```ruby
inventory = Inventory.find(params: { product_id: 1 }) # => GET /products/1/inventory.json
# BEFORE
inventory.get(:report, product_id: 1) # => GET /products/1/inventories/report.json
inventory.delete(:reset, product_id: 1) # => DELETE /products/1/inventories/reset.json
```
Note the `/inventories/` portion of the URL prefix. The same occurs for
class methods. For example, consider calls to the same custom "report"
and "reset" routes for a singleton `Inventory` resource class:
```ruby
# BEFORE
Inventory.get(:report, product_id: 1) # => GET /products/1/inventories/report.json
Inventory.delete(:reset, product_id: 1) # => DELETE /products/1/inventories/reset.json
```
The proposal
---
In order to make "singleton" resources behave more consistently with a
singular mental model, this commit proposes that Active Resource change
instance-level custom methods (through the same `get`, `post`, `put`,
`patch`, and `delete` style methods) to use the singular singleton name
in their paths.
When declaring a resource as a "singleton" (through including the
`ActiveResource::Singleton` module), ensure that subsequent calls to
class-level custom methods (through the `get`, `post`, `put`, `patch`,
and `delete` class and instance methods) use the singleton name by
default.
```ruby
# AFTER
Inventory.get(:report, product_id: 1) # => GET /products/1/inventory/report.json
Inventory.delete(:reset, product_id: 1) # => DELETE /products/1/inventory/reset.json
```
When a `collection_name` is explicitly configured, use that value
instead of the `singleton_name` default.
Apply the same changes to instances of singleton resources:
```ruby
inventory = Inventory.find(params: { product_id: 1 }) # => GET /products/1/inventory.json
# AFTER
inventory.get(:report) # => GET /products/1/inventory/report.json
inventory.delete(:reset) # => DELETE /products/1/inventory/reset.json
```
0 commit comments