Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NoMethodError: undefined method `singularize' for nil:NilClass #1691

Closed
dasnixon opened this issue Apr 19, 2016 · 10 comments
Closed

NoMethodError: undefined method `singularize' for nil:NilClass #1691

dasnixon opened this issue Apr 19, 2016 · 10 comments

Comments

@dasnixon
Copy link
Contributor

dasnixon commented Apr 19, 2016

This is currently only happening in production, so I wonder if it has something to do with caching. I did try to run Rails.cache.clear and I touched a few records in the DB to see if that would fix the issue. I am running on Heroku with ruby 2.3.0 and rails 4.2.6

API Request

/api/v1/jobs?include=business&page=1&per_page=10

Culprit

https://github.com/rails-api/active_model_serializers/blob/v0.10.0.rc5/lib/active_model/serializer/fieldset.rb#L13

My Serializer

module Api
  module V1
    class JobSerializer < ActiveModel::Serializer
      cache key: 'api-v1-job'
      attributes :id, :job_role, :description, :perks, :job_type, :wage,
        :age_requirement, :posted_on, :enabled, :application_site,
        :start_timeframe, :location, :live, :highlighted, :category_list,
        :latitude, :longitude
      type :jobs

      has_one :business,
        serializer: Api::V1::BusinessSerializer,
        embed: :id,
        embed_key: :to_param

      def id
        object.to_param
      end

      def live
        object.live?
      end

      def category_list
        object.categories.pluck(:name)
      end
    end
  end
end

Overridden Collection Serializer

class NamespacedCollectionSerializer < ActiveModel::Serializer::CollectionSerializer
  def initialize(resources, options = {})
    @object                  = resources
    @options                 = options
    @root                    = options[:root]
    serializer_context_class = options.fetch(:serializer_context_class, ActiveModel::Serializer)
    namespace                = options.fetch(:namespace)
    @serializers = resources.map do |resource|
      resource_serializer = "#{resource.class.name.demodulize}Serializer"
      resource_serializer = "#{namespace}::#{resource_serializer}" if namespace.present?
      serializer_class = resource_serializer.constantize

      if serializer_class.nil? # rubocop:disable Style/GuardClause
        fail NoSerializerError, "No serializer found for resource: #{resource.inspect}"
      else
        serializer_class.new(resource, options.except(:serializer, :namespace))
      end
    end
  end
end

Stacktrace

File "/app/vendor/bundle/ruby/2.3.0/gems/active_model_serializers-0.10.0.rc5/lib/active_model/serializer/fieldset.rb" line 13 in fields_for
2
File "/app/vendor/bundle/ruby/2.3.0/gems/active_model_serializers-0.10.0.rc5/lib/active_model_serializers/adapter/json_api.rb" line 299 in resource_object_for
3
File "/app/vendor/bundle/ruby/2.3.0/gems/active_model_serializers-0.10.0.rc5/lib/active_model_serializers/adapter/json_api.rb" line 241 in process_resource
4
File "/app/vendor/bundle/ruby/2.3.0/gems/active_model_serializers-0.10.0.rc5/lib/active_model_serializers/adapter/json_api.rb" line 231 in block in resource_objects_for
5
File "/app/vendor/bundle/ruby/2.3.0/gems/active_model_serializers-0.10.0.rc5/lib/active_model/serializer/collection_serializer.rb" line 6 in each
6
File "/app/vendor/bundle/ruby/2.3.0/gems/active_model_serializers-0.10.0.rc5/lib/active_model/serializer/collection_serializer.rb" line 6 in each
7
File "/app/vendor/bundle/ruby/2.3.0/gems/active_model_serializers-0.10.0.rc5/lib/active_model_serializers/adapter/json_api.rb" line 231 in resource_objects_for
8
File "/app/vendor/bundle/ruby/2.3.0/gems/active_model_serializers-0.10.0.rc5/lib/active_model_serializers/adapter/json_api.rb" line 74 in success_document
9
File "/app/vendor/bundle/ruby/2.3.0/gems/active_model_serializers-0.10.0.rc5/lib/active_model_serializers/adapter/json_api.rb" line 49 in serializable_hash
10
File "/app/vendor/bundle/ruby/2.3.0/gems/active_model_serializers-0.10.0.rc5/lib/active_model_serializers/adapter/base.rb" line 27 in as_json
11
File "/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/json/encoding.rb" line 35 in encode
12
File "/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/json/encoding.rb" line 22 in encode
13
File "/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/core_ext/object/json.rb" line 37 in to_json_with_active_support_encoder
14
File "/app/vendor/ruby-2.3.0/lib/ruby/2.3.0/delegate.rb" line 341 in block in delegating_block
15
File "/app/vendor/bundle/ruby/2.3.0/gems/active_model_serializers-0.10.0.rc5/lib/active_model_serializers/serializable_resource.rb" line 8 in to_json 
16
File "/app/vendor/bundle/ruby/2.3.0/gems/active_model_serializers-0.10.0.rc5/lib/active_model_serializers/logging.rb" line 69 in block (3 levels) in notify
17
File "/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/callbacks.rb" line 117 in call
18
File "/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/callbacks.rb" line 555 in block (2 levels) in compile
19
File "/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/callbacks.rb" line 505 in call
20
File "/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/callbacks.rb" line 498 in block (2 levels) in around
21
File "/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/callbacks.rb" line 343 in block (2 levels) in simple
22
File "/app/vendor/bundle/ruby/2.3.0/gems/active_model_serializers-0.10.0.rc5/lib/active_model_serializers/logging.rb" line 22 in block (3 levels) in instrument_rendering
23
File "/app/vendor/bundle/ruby/2.3.0/gems/active_model_serializers-0.10.0.rc5/lib/active_model_serializers/logging.rb" line 79 in block in notify_render
24
File "/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/notifications.rb" line 164 in block in instrument
25
File "/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/notifications/instrumenter.rb" line 20 in instrument
26
File "/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/notifications.rb" line 164 in instrument
27
File "/app/vendor/bundle/ruby/2.3.0/gems/active_model_serializers-0.10.0.rc5/lib/active_model_serializers/logging.rb" line 78 in notify_render
28
File "/app/vendor/bundle/ruby/2.3.0/gems/active_model_serializers-0.10.0.rc5/lib/active_model_serializers/logging.rb" line 21 in block (2 levels) in instrument_rendering
29
File "/app/vendor/bundle/ruby/2.3.0/gems/active_model_serializers-0.10.0.rc5/lib/active_model_serializers/logging.rb" line 95 in block in tag_logger
30
File "/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/tagged_logging.rb" line 68 in block in tagged
31
File "/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/tagged_logging.rb" line 26 in tagged
32
File "/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/tagged_logging.rb" line 68 in tagged
33
File "/app/vendor/bundle/ruby/2.3.0/gems/active_model_serializers-0.10.0.rc5/lib/active_model_serializers/logging.rb" line 95 in tag_logger
34
File "/app/vendor/bundle/ruby/2.3.0/gems/active_model_serializers-0.10.0.rc5/lib/active_model_serializers/logging.rb" line 20 in block in instrument_rendering
35
File "/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/callbacks.rb" line 441 in instance_exec
36
File "/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/callbacks.rb" line 441 in block in make_lambda
37
File "/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/callbacks.rb" line 342 in block in simple
38
File "/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/callbacks.rb" line 497 in block in around
39
File "/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/callbacks.rb" line 505 in call
40
File "/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/callbacks.rb" line 92 in __run_callbacks__
41
File "/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/callbacks.rb" line 778 in _run_render_callbacks
42
File "/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/callbacks.rb" line 81 in run_callbacks
43
File "/app/vendor/bundle/ruby/2.3.0/gems/active_model_serializers-0.10.0.rc5/lib/active_model_serializers/logging.rb" line 68 in block (2 levels) in notify
44
File "/app/vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_controller/metal/renderers.rb" line 116 in block in <module:Renderers>
45
File "/app/vendor/bundle/ruby/2.3.0/gems/active_model_serializers-0.10.0.rc5/lib/action_controller/serialization.rb" line 52 in block (2 levels) in <module:Serialization>
46
File "/app/vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_controller/metal/renderers.rb" line 45 in block in _render_to_body_with_renderer 
47
File "/app/vendor/ruby-2.3.0/lib/ruby/2.3.0/set.rb" line 306 in each_key
48
File "/app/vendor/ruby-2.3.0/lib/ruby/2.3.0/set.rb" line 306 in each
49
File "/app/vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_controller/metal/renderers.rb" line 41 in _render_to_body_with_renderer
50
File "/app/vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_controller/metal/renderers.rb" line 37 in render_to_body
51
File "/app/vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/abstract_controller/rendering.rb" line 25 in render
52
File "/app/vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_controller/metal/rendering.rb" line 16 in render
53
File "/app/vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_controller/metal/instrumentation.rb" line 44 in block (2 levels) in render
54
File "/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/core_ext/benchmark.rb" line 12 in block in ms
55
File "/app/vendor/ruby-2.3.0/lib/ruby/2.3.0/benchmark.rb" line 308 in realtime
56
File "/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/core_ext/benchmark.rb" line 12 in ms
57
File "/app/vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_controller/metal/instrumentation.rb" line 44 in block in render
58
File "/app/vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_controller/metal/instrumentation.rb" line 87 in cleanup_view_runtime
59
File "/app/vendor/bundle/ruby/2.3.0/gems/activerecord-4.2.6/lib/active_record/railties/controller_runtime.rb" line 25 in cleanup_view_runtime
60
File "/app/vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_controller/metal/instrumentation.rb" line 43 in render
61
File "/app/app/controllers/concerns/api_response.rb" line 51 in render_resource
62
File "/app/app/controllers/concerns/api_response.rb" line 22 in respond_with
63
File "/app/app/controllers/api/v1/jobs_controller.rb" line 32 in index
@beauby
Copy link
Contributor

beauby commented Apr 19, 2016

What seems to be happening here is that somehow the type of the resource is not being properly determined. I suspect this line to be responsible. cc @remear

@dasnixon
Copy link
Contributor Author

After some debugging locally and turning on caching I was able to reproduce
the issue. The cache lookup returns an object with they keys as strings.
This is trying to lookup by symbol which is causing the nil. I can submit a
PR but it uses with_indifferent_access. I know that's not efficient.

On Tuesday, April 19, 2016, Lucas Hosseini notifications@github.com wrote:

What seems to be happening here is that somehow the type of the resource
is not being properly determined. I suspect this line
https://github.com/rails-api/active_model_serializers/blob/v0.10.0.rc5/lib/active_model_serializers/adapter/json_api/resource_identifier.rb#L8
to be responsible. cc @remear https://github.com/remear


You are receiving this because you authored the thread.
Reply to this email directly or view it on GitHub
#1691 (comment)

-Chris Nixon

@beauby
Copy link
Contributor

beauby commented Apr 20, 2016

Oh, interesting catch! cc @bf4

@dasnixon
Copy link
Contributor Author

screen shot 2016-04-19 at 5 13 32 pm

@dasnixon
Copy link
Contributor Author

dasnixon commented Apr 20, 2016

Per @beauby as of writing this (caching will be fully working in a future release), caching slows down response time. Therefore, the quickest fix for this was to disable caching altogether, which I did by removing the line cache key....

module Api
  module V1
    class JobSerializer < ActiveModel::Serializer
      # (REMOVE THIS) cache key: 'api-v1-job'
      attributes :id, :job_role, :description, :perks, :job_type, :wage,
        :age_requirement, :posted_on, :enabled, :application_site,
        :start_timeframe, :location, :live, :highlighted, :category_list,
        :latitude, :longitude
      type :jobs

@ianks
Copy link

ianks commented Apr 20, 2016

I have also been experiencing some bugs with the newest changes to caching.

I was caching like this:

3   cache
4 
5   delegate :cache_key, to: :object

And would get errors like this:

NoMethodError: undefined method `utc' for nil:NilClass

Backtrace

[GEM_ROOT]/bundler/gems/rails-2d744fee9c05/activerecord/lib/active_record/integration.rb:61 :in `cache_key`
[PROJECT_ROOT]/app/serializers/smart_tip_serializer.rb:5 :in `cache_key`
[GEM_ROOT]/bundler/gems/active_model_serializers-7485c8487ee6/lib/active_model/serializer/caching.rb:220 :in `cache_check`
[GEM_ROOT]/bundler/gems/active_model_serializers-7485c8487ee6/lib/active_model_serializers/adapter/base.rb:39 :in `cache_check`
[GEM_ROOT]/bundler/gems/active_model_serializers-7485c8487ee6/lib/active_model_serializers/adapter/json_api.rb:289 :in `resource_object_for`
[GEM_ROOT]/bundler/gems/active_model_serializers-7485c8487ee6/lib/active_model_serializers/adapter/json_api.rb:240 :in `process_resource`

@beauby
Copy link
Contributor

beauby commented Apr 20, 2016

cc @bf4

@bf4
Copy link
Member

bf4 commented Apr 20, 2016

@ianks re:

delegate :cache_key, to: :object

So, in master this is actually now the default case. see #1642

def object_cache_key
if object.respond_to?(:cache_key)
object.cache_key
elsif (serializer_cache_key = (self.class._cache_key || self.class._cache_options[:key]))
object_time_safe = object.updated_at
object_time_safe = object_time_safe.strftime('%Y%m%d%H%M%S%9N') if object_time_safe.respond_to?(:strftime)
"#{serializer_cache_key}/#{object.id}-#{object_time_safe}"
else
fail UndefinedCacheKey, "#{object.class} must define #cache_key, or the 'key:' option must be passed into '#{self.class}.cache'"
end

I'm not sure where the utc error would be coming from.

@adaam2
Copy link

adaam2 commented Dec 6, 2017

@bf4 If you're delegating cache_key to object (like @ianks is above) then it passes through to the cache key method as defined by AR:

"/usr/local/bundle/gems/activerecord-4.2.9/lib/active_record/integration.rb:61:in `cache_key'\n",
 "/app/app/serializers/base_serializer.rb:8:in `cache_key'\n",
 "/usr/local/bundle/gems/active_model_serializers-0.10.5/lib/active_model/serializer/concerns/caching.rb:207:in `fetch_attributes'\n",
 "/usr/local/bundle/gems/active_model_serializers-0.10.5/lib/active_model/serializer.rb:166:in `serializable_hash'\n"

So therefore object is nil for some reason, which tends to suggest that something is awry with AMS

@bf4
Copy link
Member

bf4 commented Dec 7, 2017

@adaam2 Please open a new issue. I'm not sure why you're defining delegate :cache_key, to: :object, but that's not expected

@rails-api rails-api locked and limited conversation to collaborators Dec 7, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

6 participants