ruby-grape / grape-active_model_serializers

User active_model_serializers with Grape
MIT License
140 stars 68 forks source link

undefined method `deconstantize' for nil:NilClass #70

Closed ivan-garanin closed 7 years ago

ivan-garanin commented 7 years ago

Hello,

Im using Grape, sequel, rake and grape-active_model_serializers( no rails ) for my little application.

Here is code of problem place

helpers do
 def dictionaries_collection
    @dictionaries_collection ||= if params[:page].present?
      DictionarySearch.new(search_params).results.paginate(params[:page], params[:per] ? params[:per] : 50)
    else
      DictionarySearch.new(search_params).results
    end
  end
end

namespace :dictionaries do
  # GET dictionaries
  desc 'List of dictionaries ', {
    http_codes: [
      [200, 'Ok']
    ]
  }

  params do
    optional :per, type: Integer, desc: 'Records count on a page'
    optional :page, type: Integer, default: 1, desc: 'Page number'
    optional :q, type: Hash do
      optional :name_like, type: String, desc: 'Name includes …'
      optional :ancestor_id, type: Integer, desc: 'Parent id'
    end
  end

  get '/', each_serialize: DictionarySerializer do
    dictionaries_collection
  end
end

When im trying to take list of dictionaries im taking such error

Here is backtrace

caught error of type NoMethodError in after callback inside Grape::Middleware::Formatter : undefined method `deconstantize' for nil:NilClass
NoMethodError: undefined method `deconstantize' for nil:NilClass
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/grape-active_model_serializers-1.5.0/lib/grape-active_model_serializers/serializer_resolver.rb:82:in `resource_namespace'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/grape-active_model_serializers-1.5.0/lib/grape-active_model_serializers/serializer_resolver.rb:72:in `resource_serializer_klass'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/grape-active_model_serializers-1.5.0/lib/grape-active_model_serializers/serializer_resolver.rb:58:in `namespace_inferred_class'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/grape-active_model_serializers-1.5.0/lib/grape-active_model_serializers/serializer_resolver.rb:22:in `serializer_class'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/grape-active_model_serializers-1.5.0/lib/grape-active_model_serializers/serializer_resolver.rb:10:in `serializer'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/grape-active_model_serializers-1.5.0/lib/grape-active_model_serializers/formatter.rb:27:in `fetch_serializer'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/grape-active_model_serializers-1.5.0/lib/grape-active_model_serializers/formatter.rb:7:in `call'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/grape-0.19.2/lib/grape/middleware/formatter.rb:44:in `block in build_formatted_response'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/grape-0.19.2/lib/grape/middleware/formatter.rb:44:in `collect'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/grape-0.19.2/lib/grape/middleware/formatter.rb:44:in `build_formatted_response'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/grape-0.19.2/lib/grape/middleware/formatter.rb:28:in `after'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/grape-0.19.2/lib/grape/middleware/base.rb:34:in `call!'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/grape-0.19.2/lib/grape/middleware/base.rb:24:in `call'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/grape-0.19.2/lib/grape/middleware/error.rb:34:in `block in call!'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/grape-0.19.2/lib/grape/middleware/error.rb:33:in `catch'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/grape-0.19.2/lib/grape/middleware/error.rb:33:in `call!'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/grape-0.19.2/lib/grape/middleware/base.rb:24:in `call'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/rack-2.0.1/lib/rack/head.rb:12:in `call'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/grape-0.19.2/lib/grape/endpoint.rb:224:in `call!'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/grape-0.19.2/lib/grape/endpoint.rb:218:in `call'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/grape-0.19.2/lib/grape/router/route.rb:72:in `exec'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/grape-0.19.2/lib/grape/router.rb:119:in `process_route'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/grape-0.19.2/lib/grape/router.rb:74:in `block in identity'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/grape-0.19.2/lib/grape/router.rb:93:in `transaction'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/grape-0.19.2/lib/grape/router.rb:72:in `identity'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/grape-0.19.2/lib/grape/router.rb:57:in `block in call'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/grape-0.19.2/lib/grape/router.rb:135:in `with_optimization'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/grape-0.19.2/lib/grape/router.rb:56:in `call'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/grape-0.19.2/lib/grape/api.rb:119:in `call'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/grape-0.19.2/lib/grape/api.rb:45:in `call!'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/grape-0.19.2/lib/grape/api.rb:40:in `call'
    /home/ivan/workspace/rest-nsi/app/app.rb:19:in `call'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/rack-cors-0.4.0/lib/rack/cors.rb:80:in `call'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/rack-2.0.1/lib/rack/tempfile_reaper.rb:15:in `call'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/rack-2.0.1/lib/rack/lint.rb:49:in `_call'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/rack-2.0.1/lib/rack/lint.rb:37:in `call'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/rack-2.0.1/lib/rack/show_exceptions.rb:23:in `call'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/rack-2.0.1/lib/rack/common_logger.rb:33:in `call'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/rack-2.0.1/lib/rack/chunked.rb:54:in `call'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/rack-2.0.1/lib/rack/content_length.rb:15:in `call'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/puma-3.8.2/lib/puma/configuration.rb:224:in `call'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/puma-3.8.2/lib/puma/server.rb:600:in `handle_request'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/puma-3.8.2/lib/puma/server.rb:435:in `process_client'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/puma-3.8.2/lib/puma/server.rb:299:in `block in run'
    /home/ivan/.rvm/gems/ruby-2.3.1/gems/puma-3.8.2/lib/puma/thread_pool.rb:120:in `block in spawn_thread'

All other routes(get(id), patch, all other) which are working with single record(not array) are fine.

Could you help me with this issue?

ivan-garanin commented 7 years ago

Here is my base grape file

module Nsi
  class API < Grape::API
    format :json
    formatter :json, Grape::Formatter::ActiveModelSerializers

    mount Nsi::DictionaryResource
    mount Nsi::ParameterResource
    mount Nsi::DictionaryParameterResource

    add_swagger_documentation :format => :json,
                              :hide_documentation_path => true,
                              :mount_path => 'swagger_doc'
  end
end
ivan-garanin commented 7 years ago

same error without option

each_serialize: DictionarySerializer
ivan-garanin commented 7 years ago

Looks like i have got anonymous class a = Class.new; a.name => nil in Grape::ActiveModelSerializers::SerializerResolver in instance initialization something like Grape::ActiveModelSerializers::SerializerResolver.new(Class.new, opts)

hm... I already have got it there...

module Grape
  module Formatter
    module ActiveModelSerializers
      class << self
        def call(resource, env)
          # !!!! resource.class.name => nil, resource.class => #<Class:0x005...>
          options = build_options(resource, env)
          serializer = fetch_serializer(resource, options)

          if serializer
            ::ActiveModelSerializers::Adapter.create(
              serializer, options
            ).to_json
          else
            Grape::Formatter::Json.call(resource, env)
          end
        end

        def build_options(resource, env)
          Grape::ActiveModelSerializers::OptionsBuilder.new(
            resource, env
          ).options
        end

        def fetch_serializer(resource, options)
          Grape::ActiveModelSerializers::SerializerResolver.new(
            resource, options
          ).serializer
        end
      end
    end
  end
end

hm... I need help guys :(' What I'm doing wrong?

drn commented 7 years ago

Hi @ivan-garanin, is there a project that I would be able to reproduce this error in? If I can replicate the error, I can look into patching it

ivan-garanin commented 7 years ago

Hi @drn , I'll publish on github my cutted project for you tomorrow.

ivan-garanin commented 7 years ago

@drn, I made example app(with all same configs/settings and so on) https://github.com/ivan-garanin/example-for-grape_active_model_serializer check readme to launch it faster

drn commented 7 years ago

Thanks for providing that project, @ivan-garanin

I dug into our source code via your project and it looks like neither this gem or active_model_serializers have great support for non-ActiveRecord ORMs. Both gems key off of collection resources responding to a to_ary method that ActiveRecord has implemented for collections, but Sequel does not.

That said, I implemented some basic support for sequel that you can try out. https://github.com/ruby-grape/grape-active_model_serializers/pull/74

I tested this against your project:

gem 'grape-active_model_serializers',
  github: 'ruby-grape/grape-active_model_serializers',
  branch: 'support-sequel'

Let me know if it works for you!

ivan-garanin commented 7 years ago

@drn thank you!

drn commented 7 years ago

👍 worked? ill get that merged in over the next few days and release a new gem version

ivan-garanin commented 7 years ago

yea, everything is OK, ty for help, ping me when release ll be ready and I'd remove that ugly line from Gemfile)

drn commented 7 years ago

v1.5.1 has been released!