JSONAPI-Resources / JSONAPI-Resources/jsonapi-resources

Custom filters sometimes work incorrectly for nested routes

Open
#1,374 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Ruby
Stars
2.3k
Forks
546
PR merge metrics
No merged PRs in 30d

Description

This issue is a (choose one):

  • Problem/bug report.
  • Feature request.
  • Request for support. Note: Please try to avoid submitting issues for support requests. Use Gitter instead.

Checklist before submitting:

  • I've searched for an existing issue.
  • I've asked my question on Gitter and have not received a satisfactory answer.
  • I've included a complete bug report template. This step helps us and allows us to see the bug without trying to reproduce the problem from your description. It helps you because you will frequently detect if it's a problem specific to your project.
  • The feature I'm asking for is compliant with the JSON:API spec.

Description

Bug reports:

Gem version 0.10.5.

EDIT: After submitting this, I realized that this might not be considered a bug so much as a limitation due to how ActiveRecord joins work. It might be a good idea, however, to include a caveat in the documentation that table name must be specified in filters so as not to break join queries.

When using a custom filter (i.e. one defined with an apply lambda) on a nested route (/foos/:id/bars), the filter is applied on the parent model (Foo) instead of the child model (Bar), when the child model's table name is not specified in the filter query.

Example:
class AuthorResource < JSONAPI::Resource
  has_many :books
end
class BookResource < JSONAPI::Resource
  has_one :author 
  attributes :title

  filter :title

  filter :_title, apply: ->(records, value, _options){
    records.where(title: value)
  }
end

Rails returns the expected response for http://localhost:3000/authors/1/books?filter[title]=book1:

{"data":[
  {"id":"1",
   "type":"books",
   "links":{
    "self":"http://localhost:3000/books/1"
   },
   "attributes":{
     "title":"book1"
   },
   "relationships":{
     "author":{
       "links":{
         "self":"http://localhost:3000/books/1/relationships/author",
         "related":"http://localhost:3000/books/1/author"}}}}]}

But not for http://localhost:3000/authors/1/books?filter[_title]=book1

{"errors":[
  {"title":"Internal Server Error",
   "detail":"Internal Server Error",
   "code":"500",
   "status":"500",
   "meta":{
     "exception":"SQLite3::SQLException: no such column: authors.title",
     "backtrace":[...],
     "application_backtrace":[]}}]}

So, with filter[title], the filter is applied on Book, whereas with filter[_title], it is is instead applied on Author, in this case causing the error SQLite3::SQLException: no such column: authors.title, since the Author model does not have the attribute title.

filter[_title] does work, however, if we instead define it as:

  filter :_title, apply: ->(records, value, _options){
    records.where(books: {title: value})
  }

So I suppose applying the two versions of _title on records results in something like:

Author.joins(:books).where(title: 'book1')

and

Author.joins(:books).where(books: {title: 'book1'})

respectively, where the first one does not work as intended.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the nested /authors/:id/books request with both the built-in title filter and the custom _title filter, then trace how custom filter apply lambdas receive records for nested routes. Compare the generated ActiveRecord join conditions and add a regression test or document the table-name requirement, depending on the intended behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
rails, ruby
Domain
api, backend, database
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.