Skip to content

NoMethodError: undefined method `[]=' for #<Grape::Entity::Options:0x007fc6a6f1a7b0> #206

@mcls

Description

@mcls

When you have an entity which exposes an ActiveRecord belongs_to without a :using option, then serializable_hash is called with a Grape::Entity::Options object.

But serializable_hash clones the object and then tries to set :except on it. (It sets default :except to an empty array see here.) This causes the exception:

NoMethodError: undefined method '[]=' for #<Grape::Entity::Options:0x007fc6a6f1a7b0>

Not too big of a problem, it was just a forgotten :using, but it was very confusing.
Also depending on whether it's an object, array or hash, serializable_hash is called with or without options.

I'm talking about the code in Grape::Entity::Exposure::Base#serializable_value.

Should the options even be passed to serializable_hash at all? Or should []= be implemented?
This did work up until this commit btw.

Example to reproduce:

class Author < ActiveRecord::Base
end

class Post < ActiveRecord::Base
  belongs_to :author
end

class PostEntity < Grape::Entity
  expose :author # notice missing :using
end

PostEntity.represent(Post.first).as_json # => NoMethodError

Activity

dblock

dblock commented on Feb 2, 2016

@dblock
Member

I agree that this is confusing, and the error is not helpful. I am not sure what to do though, I guess the real question is what we'd like to see?

mcls

mcls commented on Feb 8, 2016

@mcls
Author

Instead of relying on serializable_hash, maybe checking whether the object is a JSON primitive?
Then if it isn't a primitive, you can raise an exception, saying that the :using should be specified.
Maybe provide an option to fallback to serializable_hash or another method.

In multi_json they do this:
https://github.com/intridea/multi_json/blob/1ba3be42600696f676d9cc1f029227b84c3c763b/lib/multi_json/convertible_hash_keys.rb#L17-L40

    def prepare_hash(hash, &key_modifier)
      return hash unless block_given?
      case hash
      when Array
        hash.map do |value|
          prepare_hash(value, &key_modifier)
        end
      when Hash
        hash.inject({}) do |result, (key, value)|
          new_key   = key_modifier.call(key)
          new_value = prepare_hash(value, &key_modifier)
          result.merge! new_key => new_value
        end
      when String, Numeric, true, false, nil
        hash
      else
        if hash.respond_to?(:to_json)
          hash
        elsif hash.respond_to?(:to_s)
          hash.to_s
        else
          hash
        end
      end

What do you think?

dblock

dblock commented on Feb 8, 2016

@dblock
Member

I think it's a good strategy, try to PR?

mcls

mcls commented on Feb 10, 2016

@mcls
Author

Looks like this will be hard to do without introducing any breaking changes. The code relies pretty heavily on serializable_hash.

I'll post my spike branch later, once I get a chance to clean it up a bit.

bambam247

bambam247 commented on Apr 30, 2016

@bambam247

I am running into this exact error with grape-entity (0.5.1). It occurs on gitlab 8.6.6 when requesting api/v3/projects and anything below. Is there anything I can do to get this functionality working? Is there possibly a version I could safely downgrade to?

thanks

dblock

dblock commented on May 2, 2016

@dblock
Member

@bambam247 Are you sure you have the same problem? In here the workaround is to use using and we're discussing producing a more helpful error.

dja

dja commented on Jun 6, 2016

@dja

@dblock I'm using using and getting the same error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @dblock@mcls@dja@bambam247

        Issue actions

          NoMethodError: undefined method `[]=' for #<Grape::Entity::Options:0x007fc6a6f1a7b0> · Issue #206 · ruby-grape/grape-entity