Skip to content

Included assuming default class name to build Serializers #35

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

Closed
hlegius opened this issue Dec 7, 2015 · 10 comments
Closed

Included assuming default class name to build Serializers #35

hlegius opened this issue Dec 7, 2015 · 10 comments

Comments

@hlegius
Copy link

hlegius commented Dec 7, 2015

Hello there!

I am trying to build a included JSON API schema within my Serializer, but I am got an error while try to find the serializer class.

I've got:

  uninitialized constant Some::Other::Namespace::RequesterSerializer
     # /Users/hlegius/.rvm/gems/ruby-2.2.1@awesome-project/gems/activesupport-4.2.4/lib/active_support/inflector/methods.rb:263:in `const_get'
     # /Users/hlegius/.rvm/gems/ruby-2.2.1@awesome-project/gems/activesupport-4.2.4/lib/active_support/inflector/methods.rb:263:in `block in constantize'
     # /Users/hlegius/.rvm/gems/ruby-2.2.1@awesome-project/gems/activesupport-4.2.4/lib/active_support/inflector/methods.rb:259:in `each'
     # /Users/hlegius/.rvm/gems/ruby-2.2.1@awesome-project/gems/activesupport-4.2.4/lib/active_support/inflector/methods.rb:259:in `inject'
     # /Users/hlegius/.rvm/gems/ruby-2.2.1@awesome-project/gems/activesupport-4.2.4/lib/active_support/inflector/methods.rb:259:in `constantize'
     # /Users/hlegius/.rvm/gems/ruby-2.2.1@awesome-project/gems/activesupport-4.2.4/lib/active_support/core_ext/string/inflections.rb:66:in `constantize'
     # /Users/hlegius/.rvm/gems/ruby-2.2.1@awesome-project/gems/jsonapi-serializers-0.3.0/lib/jsonapi-serializers/serializer.rb:210:in `find_serializer_class'
     # /Users/hlegius/.rvm/gems/ruby-2.2.1@awesome-project/gems/jsonapi-serializers-0.3.0/lib/jsonapi-serializers/serializer.rb:214:in `find_serializer'
     # /Users/hlegius/.rvm/gems/ruby-2.2.1@awesome-project/gems/jsonapi-serializers-0.3.0/lib/jsonapi-serializers/serializer.rb:351:in `block in find_recursive_relationships'
     # /Users/hlegius/.rvm/gems/ruby-2.2.1@awesome-project/gems/jsonapi-serializers-0.3.0/lib/jsonapi-serializers/serializer.rb:347:in `each'
     # /Users/hlegius/.rvm/gems/ruby-2.2.1@awesome-project/gems/jsonapi-serializers-0.3.0/lib/jsonapi-serializers/serializer.rb:347:in `find_recursive_relationships'
     # /Users/hlegius/.rvm/gems/ruby-2.2.1@awesome-project/gems/jsonapi-serializers-0.3.0/lib/jsonapi-serializers/serializer.rb:290:in `block in serialize'
     # /Users/hlegius/.rvm/gems/ruby-2.2.1@awesome-project/gems/jsonapi-serializers-0.3.0/lib/jsonapi-serializers/serializer.rb:287:in `each'
     # /Users/hlegius/.rvm/gems/ruby-2.2.1@awesome-project/gems/jsonapi-serializers-0.3.0/lib/jsonapi-serializers/serializer.rb:287:in `serialize'
     # /Users/hlegius/.rvm/gems/ruby-2.2.1@awesome-project/gems/jsonapi-serializers-0.3.0/lib/jsonapi-serializers/serializer.rb:20:in `serialize'

My implementation:

# Requester Serializer
module My
  module Awesome
    module Responders
      class Requester
        include JSONAPI::Serializer

        has_one :mailing_address
        has_one :shipping_address

        attribute :foo
        attribute :bar
      end
    end
  end
end

# Address Serializer 
module My
  module Awesome
    module Responders
      class Address
        include JSONAPI::Serializer

        attribute :zip_code
      end
    end
  end
end

# Domain Entity
module Some
  module Other
    module Namespace
      class Requester
        # ...

        def mailing_address
          # ...
        end

        def shipping_address
          # ...
        end
      end
    end
  end
end

# Returns Some::Other::Namespace::Requester object
requester = Some::Other::Namespace::RequesterRepository.find(...) 

My::Awesome::Responders::Requester.serialize(requester) # runs pretty well, thanks!
My::Awesome::Responders::Requester.serialize(
  requester,
  include: ['mailing_address', 'shipping_address']
) # fail with the error above.

So, as far as I've debugged, it's when ActiveSupport .constantize that tries to build a Some::Other::Namespace::RequesterSerializer with some fixed convention created within serialize.rb file.

Documentation says that it's possible to customize this behavior, but I didn't figure out who to do this.

If you need further informations, I am totally willing to help to understand/solve this o/

Thanks for reading!

@fotinakis
Copy link
Owner

Per the docs, use JSONAPI::Serializer.serialize(requester), not My::Awesome::Responders::Requester.serialize. Let me know if that doesn't work.

@hlegius
Copy link
Author

hlegius commented Dec 8, 2015

@fotinakis thanks for reply. I've tried with JSONAPI::Serializer but I got the same error:

JSONAPI::Serializer.serialize(
  requester,
  include: ['mailing_address', 'shipping_address']
) # fail with the error above.

@fotinakis
Copy link
Owner

After looking through the code I'm not sure if we support this very well. You may want to try passing through the serializer option:

JSONAPI::Serializer.serialize(requester, serializer: My::Awesome::Responders::Requester)

But, I'm not sure if relationships will work well. There are some architecture changes we need to make to support this (somewhat discussed in #18) -- sorry we don't have a better answer for this namespace handling right now.

@hlegius
Copy link
Author

hlegius commented Dec 9, 2015

@fotinakis I've read some code and had tested this option as well.
This #18 issue is closed. What's your current roadmap? I'd like to help designing/implementing this issue/feature. If you allow me, I totally would try some progress here, after get know your thoughts about it.

I saw there is some dependency with ActiveSupport within this .serialize method that maybe worth some work to remove it.

Thanks!

@fotinakis
Copy link
Owner

Actually #18 is still open, what looks closed at the bottom is a related issue. And the ActiveSupport dependency has been discussed here: #33 (but that is not related to this issue).

I think the best fix here is to add support like mentioned in #18 (comment) for defining a method on objects called jsonapi_serializer_class_name which, if defined, points to where the serializer class for the object can be found (which will be used instead of the auto-discovery)—this is option 1. Option 2 is to provide a publicly accessible way of overriding our find_serializer method via a configuration or something else, so that you can write your own logic for serializer discovery. I like this less because it involves more global state, I think I option 1 is the right way to go.

I've added this here: #37

Can you try this and let me know if it works for you? It's in the explicit-serializer-discovery branch and you'll need to define a jsonapi_serializer_class_name method on your objects, just like https://github.com/fotinakis/jsonapi-serializers/pull/37/files#diff-657d547770d779a8ddaf75831ea58904L19 .

If that works for you, I'll add documentation and merge it in.

@fotinakis fotinakis reopened this Dec 10, 2015
@fotinakis
Copy link
Owner

@hlegius Let me know if you have time to test the explicit-serializer-discovery branch and if it fixes this problem.

@hlegius
Copy link
Author

hlegius commented Dec 15, 2015

@fotinakis sure, no probls! I'll do it this along this week and keep you posted here.

@hlegius
Copy link
Author

hlegius commented Dec 23, 2015

@fotinakis sorry for delay. It worked as expected (in the Specs). Thanks! 💯

Just one thought about it: I needed to kinda couple my Entity in its Serializer. i.e.

class User
   # entity class (inside domain layer)
  def initialize(..)
  end

  def entity_method...
  end

  def jsonapi_serializer_class_name
    # UserRepresenter class name
  end
end

class UserRepresenter
  # serializer (inside Presentation layer)
  attribute :full_name
end

It creates a dependency multi-tier between User (as Entity) and UserRepresenter (as Serializer) It would bring us some complexity later if we need to split both application tiers physically. What do you think about it? As far as I read JSONAPI::Serializer class, it will requires a mid/big effort to make Serializer receive the specific Serializer (acting like a dependency injection) instead of currently implementation. I mean:

user_representer = My::Weird::Namespace::UserRepresenter.new(user_entity)
JSONAPI::Serializer.serialize(user_representer, included: ['posts'])

What's your thoughts/concerns about it?

Thanks again for the fast solution o/

@hlegius
Copy link
Author

hlegius commented Jan 30, 2016

Any news on this one? Thanks!

@fotinakis
Copy link
Owner

Just merged #37 and updated the README with docs. Released as gem v0.5.0. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants