ruby-grape/grape-active_model_serializers

Namespaces with associations

Closed this issue · 2 comments

Hi, I have a bunch of serializers which have associations. Unfortunately I just realised when one of them links to a serializer below it in the directory structure(alpahbetically organised by module), I get an error saying Uninitialized Constant in production.

E.g.

Articles
--ArticleSerializer
Likes
--LikeSerializer
  belongs_to :user, serializer: Users::UserSerializer
  belongs_to :article, serializer: Articles::ArticleSerializer
Users
--UserSerializer

belongs_to :user, serializer: Users::UserSerializer does not work because the UserSerializer is defined after it. However, if i rename the module of Users to ABC so it looks like

ABC
--UserSerializer
Articles
--ArticleSerializer
Likes
--LikeSerializer
  belongs_to :user, serializer: ABC::UserSerializer
  belongs_to :article, serializer: Articles::ArticleSerializer

it works! Is this a bug for module processing with associations?

drn commented

Hmm, it is difficult to know what error you are seeing without the backtrace or an example app. From the sound of it, this seems like a constant conflict issue in your project rather than a grape-ams issue.

I suspect that you may be running into a top-level constant reuse issue. You mentioned this is in prod - are you not running into this locally? If you are not running into this locally, then assuming you are using Rails, it could be due to the eager load vs auto load strategy differences.

Can you try setting belongs_to :user, serializer: ::Users::UserSerializer (add a :: before the Users)?

Either way, providing the backtrace (if useful) or an example app would help us isolate the issue.

Thanks for replying. I actually fixed this by just simply putting a require '{path}/UserSerializer' at the top.

Below is my actual stacktrace for the app I'm developing. User has many Lists. And you are right I am using Rails and this error only occurs in production.

/var/app/current/app/serializers/V1/Lists/list_serializer.rb:10:in `<class:ListSerializer>': uninitialized constant V1::Users::UserSerializer (NameError)
        from /var/app/current/app/serializers/V1/Lists/list_serializer.rb:9:in `<module:Lists>'
        from /var/app/current/app/serializers/V1/Lists/list_serializer.rb:2:in `<module:V1>'
        from /var/app/current/app/serializers/V1/Lists/list_serializer.rb:1:in `<top (required)>'
        from /opt/rubies/ruby-2.3.1/lib/ruby/gems/2.3.0/gems/activesupport-5.1.4/lib/active_support/dependencies/interlock.rb:12:in `block in loading'
        from /opt/rubies/ruby-2.3.1/lib/ruby/gems/2.3.0/gems/activesupport-5.1.4/lib/active_support/concurrency/share_lock.rb:149:in `exclusive'
        from /opt/rubies/ruby-2.3.1/lib/ruby/gems/2.3.0/gems/activesupport-5.1.4/lib/active_support/dependencies/interlock.rb:11:in `loading'
        from /opt/rubies/ruby-2.3.1/lib/ruby/gems/2.3.0/gems/railties-5.1.4/lib/rails/engine.rb:476:in `block (2 levels) in eager_load!'
        from /opt/rubies/ruby-2.3.1/lib/ruby/gems/2.3.0/gems/railties-5.1.4/lib/rails/engine.rb:475:in `each'
        from /opt/rubies/ruby-2.3.1/lib/ruby/gems/2.3.0/gems/railties-5.1.4/lib/rails/engine.rb:475:in `block in eager_load!'
        from /opt/rubies/ruby-2.3.1/lib/ruby/gems/2.3.0/gems/railties-5.1.4/lib/rails/engine.rb:473:in `each'
        from /opt/rubies/ruby-2.3.1/lib/ruby/gems/2.3.0/gems/railties-5.1.4/lib/rails/engine.rb:473:in `eager_load!'
        from /opt/rubies/ruby-2.3.1/lib/ruby/gems/2.3.0/gems/railties-5.1.4/lib/rails/engine.rb:354:in `eager_load!'
        from /opt/rubies/ruby-2.3.1/lib/ruby/gems/2.3.0/gems/railties-5.1.4/lib/rails/application/finisher.rb:67:in `each'
        from /opt/rubies/ruby-2.3.1/lib/ruby/gems/2.3.0/gems/railties-5.1.4/lib/rails/application/finisher.rb:67:in `block in <module:Finisher>'
        from /opt/rubies/ruby-2.3.1/lib/ruby/gems/2.3.0/gems/railties-5.1.4/lib/rails/initializable.rb:30:in `instance_exec'
        from /opt/rubies/ruby-2.3.1/lib/ruby/gems/2.3.0/gems/railties-5.1.4/lib/rails/initializable.rb:30:in `run'
        from /opt/rubies/ruby-2.3.1/lib/ruby/gems/2.3.0/gems/railties-5.1.4/lib/rails/initializable.rb:59:in `block in run_initializers'
        from /opt/rubies/ruby-2.3.1/lib/ruby/2.3.0/tsort.rb:228:in `block in tsort_each'
        from /opt/rubies/ruby-2.3.1/lib/ruby/2.3.0/tsort.rb:350:in `block (2 levels) in each_strongly_connected_component'
        from /opt/rubies/ruby-2.3.1/lib/ruby/2.3.0/tsort.rb:431:in `each_strongly_connected_component_from'
        from /opt/rubies/ruby-2.3.1/lib/ruby/2.3.0/tsort.rb:349:in `block in each_strongly_connected_component'
        from /opt/rubies/ruby-2.3.1/lib/ruby/2.3.0/tsort.rb:347:in `each'
        from /opt/rubies/ruby-2.3.1/lib/ruby/2.3.0/tsort.rb:347:in `call'
        from /opt/rubies/ruby-2.3.1/lib/ruby/2.3.0/tsort.rb:347:in `each_strongly_connected_component'
        from /opt/rubies/ruby-2.3.1/lib/ruby/2.3.0/tsort.rb:226:in `tsort_each'
        from /opt/rubies/ruby-2.3.1/lib/ruby/2.3.0/tsort.rb:205:in `tsort_each'
        from /opt/rubies/ruby-2.3.1/lib/ruby/gems/2.3.0/gems/railties-5.1.4/lib/rails/initializable.rb:58:in `run_initializers'
        from /opt/rubies/ruby-2.3.1/lib/ruby/gems/2.3.0/gems/railties-5.1.4/lib/rails/application.rb:353:in `initialize!'
        from /var/app/current/config/environment.rb:5:in `<top (required)>'
        from config.ru:3:in `require_relative'
        from config.ru:3:in `block in <main>'
        from /opt/rubies/ruby-2.3.1/lib/ruby/gems/2.3.0/gems/rack-2.0.3/lib/rack/builder.rb:55:in `instance_eval'
        from /opt/rubies/ruby-2.3.1/lib/ruby/gems/2.3.0/gems/rack-2.0.3/lib/rack/builder.rb:55:in `initialize'
        from config.ru:in `new'
        from config.ru:in `<main>'

My class for ListSerializer is as follows:

module V1
  module Lists

    class ListSerializer < ActiveModel::Serializer
      belongs_to :user, serializer: V1::Users::UserSerializer

      attributes :id, :name, :description, :public
    end
  end
end

and directory structure as:

serializers
--V1
----Lists
------list_serializer.rb
----Users
------user_serializer.rb

I'm closing this as the require solution fixes this. Thanks for the help!