When I make a request to a custom route in my rails project using jsonapi-resources
, I get:
NoMethodError: undefined method `each_key' for nil:NilClass
0) ArticlesController when requesting latest_article succeeds
Failure/Error: serializer.serialize_to_hash(Article.latest)
NoMethodError:
undefined method `each_key' for nil:NilClass
# /Users/me/.rbenv/versions/2.7.3/gemsets/blog-api/bundler/gems/jsonapi-resources-bf4b4cd7d79d/lib/jsonapi/resource_set.rb:37:in `populate!'
# /Users/me/.rbenv/versions/2.7.3/gemsets/blog-api/bundler/gems/jsonapi-resources-bf4b4cd7d79d/lib/jsonapi/resource_serializer.rb:49:in `serialize_to_hash'
# ./app/controllers/articles_controller.rb:4:in `latest'
# /Users/me/.rbenv/versions/2.7.3/gemsets/blog-api/gems/actiontext-6.1.4.4/lib/action_text/rendering.rb:20:in `with_renderer'
# /Users/me/.rbenv/versions/2.7.3/gemsets/blog-api/gems/actiontext-6.1.4.4/lib/action_text/engine.rb:59:in `block (4 levels) in <class:Engine>'
# /Users/me/.rbenv/versions/2.7.3/gemsets/blog-api/gems/rack-2.2.3/lib/rack/etag.rb:27:in `call'
# /Users/me/.rbenv/versions/2.7.3/gemsets/blog-api/gems/rack-2.2.3/lib/rack/conditional_get.rb:27:in `call'
# /Users/me/.rbenv/versions/2.7.3/gemsets/blog-api/gems/rack-2.2.3/lib/rack/head.rb:12:in `call'
# /Users/me/.rbenv/versions/2.7.3/gemsets/blog-api/gems/railties-6.1.4.4/lib/rails/rack/logger.rb:37:in `call_app'
# /Users/me/.rbenv/versions/2.7.3/gemsets/blog-api/gems/railties-6.1.4.4/lib/rails/rack/logger.rb:26:in `block in call'
# /Users/me/.rbenv/versions/2.7.3/gemsets/blog-api/gems/railties-6.1.4.4/lib/rails/rack/logger.rb:26:in `call'
# /Users/me/.rbenv/versions/2.7.3/gemsets/blog-api/gems/rack-2.2.3/lib/rack/runtime.rb:22:in `call'
# /Users/me/.rbenv/versions/2.7.3/gemsets/blog-api/gems/rack-2.2.3/lib/rack/sendfile.rb:110:in `call'
# /Users/me/.rbenv/versions/2.7.3/gemsets/blog-api/gems/railties-6.1.4.4/lib/rails/engine.rb:539:in `call'
# /Users/me/.rbenv/versions/2.7.3/gemsets/blog-api/gems/rack-test-1.1.0/lib/rack/mock_session.rb:29:in `request'
# /Users/me/.rbenv/versions/2.7.3/gemsets/blog-api/gems/rack-test-1.1.0/lib/rack/test.rb:266:in `process_request'
# /Users/me/.rbenv/versions/2.7.3/gemsets/blog-api/gems/rack-test-1.1.0/lib/rack/test.rb:119:in `request'
# ./spec/requests/articles_controller_spec.rb:22:in `block (3 levels) in <top (required)>'
What am I doing wrong here? And more importantly, how do I fix it?
For the purposes of this question, I have a Rails project with Article
and Comment
models. I use jsonapi-resources
to generate all of the CRUD routes:
Rails.application.routes.draw do
jsonapi_resources :articles do
collection do
get :latest
end
end
jsonapi_resources :comments
end
I added a custom articles/latest
route to return the most recent article. I'm using JSONAPI::ResourceSerializer
to serialize the Article
object following the serializer documentation
class ArticlesController < JSONAPI::ResourceController
def latest
serializer = JSONAPI::ResourceSerializer.new(ArticleResource)
serializer.serialize_to_hash(Article.latest)
end
end
I wrote a spec to duplicate the error:
describe 'ArticlesController' do
let!(:articles) { create_list(:article, 10)}
context 'when requesting articles' do
it 'succeeds' do
get articles_path
expect(response).to have_http_status(:ok)
end
end
context 'when requesting latest_article' do
it 'succeeds' do
get latest_articles_path
expect(response).to have_http_status(:ok)
end
end
end
For anyone that made it this far, I have a complete MCVE project on my GitHub.
From what I can tell from debugging, serializer.serialize_to_hash
creates a JSONAPI::ResourceSet
with resource_set = JSONAPI::ResourceSet.new(source, include_related, options)
.
Here is JSONAPI::initialize
:
def initialize(source, include_related = nil, options = nil)
@populated = false
tree = if source.is_a?(JSONAPI::ResourceTree)
source
elsif source.class < JSONAPI::BasicResource
JSONAPI::PrimaryResourceTree.new(resource: source, include_related: include_related, options: options)
elsif source.is_a?(Array)
JSONAPI::PrimaryResourceTree.new(resources: source, include_related: include_related, options: options)
end
if tree
@resource_klasses = flatten_resource_tree(tree)
end
end
I don't understand the cases in the if...elsif
chain, but none of the conditions is true for me, so tree
is nil
and so @resource_classes
is also nil
.
After this, serialize_to_hash
calls resource_set.populate!
which in turn calls @resource_klasses.each_key
, but @resource_classes
is nil
.
My current assumption is that I'm doing something wrong that causes ResourceSet.initialize
to skip initializing @resource_klasses
. But I'm not sure how to fix it. Any ideas or suggestions?