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
The problem
---
When a resource queries an "index"-like endpoint and receives a response
payload that relies on URL-based pagination, it can be tedious to
deconstruct the next page's URL and transform it into a subsequent
`.where` call.
For example, consider a `Post` payload like:
```json
{
"posts": { … },
"next_page": "https://api.blog.com/posts?page=2"
}
```
In order to query the URL in the `next_page` property, the collection
parser must extract a `{ "page" => "2" }` Hash and forward it to a
`resource_class.where` call:
```ruby
def initialize(parsed = {})
@elements = parsed["posts"]
@next_page_uri = URI.parse(parsed["next_page"])
end
def next_page_params
query_string = @next_page_uri.query
URI.decode_www_form(query_string).to_h
end
def next_page
resource_class.where(next_page_params)
end
collection.next_page_params # => { "page" => "2" }
collection.next_page # => GET https://api.blog.com/posts?page=2
```
The process becomes complicated when there are other parameters
(including "array"-like keys):
```json
{
"posts": { … },
"next_page": "https://api.blog.com/posts?tags[]=Ruby&tags[]=Rails&page=2"
}
```
In this scenario, the Array created by [URI.decode_www_form][] will only
retain both `tags[]`-keyed values, but the [Array#to_h][] call will
flatten that Array into a Hash that only contains the last key. In this
case, `tags[]=Ruby` will be omitted, and the resulting Hash would be `{
"tags[]" => "Rails", "page" => "2" }`.
The proposal
---
Active Record's `.where` method supports both [String][] and [Array][]
arguments. In the context of Active Record, `String` and `Array`
arguments are in support of the underlying SQL queries to be executed.
In the context of Active Resource, the underlying format for a "query"
is an HTTP-compliant query that's encoded as an
[application/x-www-form-urlencoded][] string.
This commit proposes adding support to `Base.where` to accept both
String and Array arguments.
This support would simplify the scenario above:
```ruby
def initialize(parsed = {})
@elements = parsed["posts"]
@next_page_uri = URI.parse(parsed["next_page"])
end
def next_page
resource_class.where(@next_page_uri.query)
end
collection.next_page # => GET https://api.blog.com/posts?page=2
```
When Active Resource is loaded alongside a Rails application, rely on
[ActionDispatch::ParamBuilder.from_pairs][] to decode key-value pairs.
Otherwise, rely on [Array#to_h][].
[URI.decode_www_form]: https://docs.ruby-lang.org/en/master/URI.html#method-c-decode_www_form
[String]: https://api.rubyonrails.org/classes/ActiveRecord/QueryMethods.html#method-i-where-label-String
[Array]: https://api.rubyonrails.org/classes/ActiveRecord/QueryMethods.html#method-i-where-label-Array
[application/x-www-form-urlencoded]: https://url.spec.whatwg.org/#application/x-www-form-urlencoded
[ActionDispatch::ParamBuilder.from_pairs]: https://api.rubyonrails.org/classes/ActionDispatch/ParamBuilder.html#method-i-from_pairs
[Array#to_h]: https://docs.ruby-lang.org/en/master/Array.html#method-i-to_h
0 commit comments