【问题标题】:Serialize model for custom jsonapi resource in rails序列化rails中自定义jsonapi资源的模型
【发布时间】:2022-02-09 02:10:26
【问题描述】:

当我使用 jsonapi-resources 向我的 rails 项目中的自定义路由发出请求时,我得到:

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)>'

我在这里做错了什么?更重要的是,我该如何解决?

出于这个问题的目的,我有一个带有 ArticleComment 模型的 Rails 项目。我使用jsonapi-resources 来生成所有的 CRUD 路由:

Rails.application.routes.draw do
  jsonapi_resources :articles do
    collection do
      get :latest
    end
  end
  jsonapi_resources :comments
end

我添加了一个自定义的articles/latest 路由来返回最新的文章。我正在使用JSONAPI::ResourceSerializer 来序列化Article 之后的the serializer documentation 对象

class ArticlesController < JSONAPI::ResourceController
  def latest
    serializer = JSONAPI::ResourceSerializer.new(ArticleResource)
    serializer.serialize_to_hash(Article.latest)
  end
end

我写了一个规范来复制错误:

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

对于已经做到这一点的任何人,我有a complete MCVE project on my GitHub.

从调试中可以看出,serializer.serialize_to_hash 创建了一个带有resource_set = JSONAPI::ResourceSet.new(source, include_related, options)JSONAPI::ResourceSet

这里是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

我不了解if...elsif 链中的情况,但没有一个条件对我来说是正确的,所以treenil,所以@resource_classes 也是nil

在此之后,serialize_to_hash 调用 resource_set.populate!,后者又调用 @resource_klasses.each_key,但 @resource_classesnil

我目前的假设是我做错了导致ResourceSet.initialize 跳过初始化@resource_klasses。但我不知道如何解决它。有什么想法或建议吗?

【问题讨论】:

  • @engineersmnky 感谢您抽出宝贵时间查看此内容。但是,我无法确认。当我将puts Article.latest 添加到ArticlesController.latest 并运行'when requesting latest_article' 时,我得到#&lt;Article:0x00007fac4325c2d0&gt; 不是nil
  • @engineersmnky 我添加了一些调试时发现的更多细节。

标签: ruby-on-rails json-api jsonapi-resources


【解决方案1】:

这里的问题是serialize_to_hash 不接受ActiveRecord 对象作为参数。相反,我需要向它传递一个资源,例如:

    serializer.serialize_to_hash(ArticleResource.new(Article.latest, {}))

我觉得jsonapi-resources 可以在这里给出一个有意义的错误信息,而不是用NoMethodError 炸毁。

【讨论】:

    猜你喜欢
    • 2016-01-26
    • 2016-07-16
    • 2017-01-26
    • 2016-11-21
    • 1970-01-01
    • 1970-01-01
    • 2015-12-31
    • 2016-06-14
    • 1970-01-01
    相关资源
    最近更新 更多