Active_model_serializers: How to do collection?

Created on 10 Feb 2016  Â·  8Comments  Â·  Source: rails-api/active_model_serializers

:star2: What i want to do...

This is the output i want:

{
  "status": "ok",
  "collection": [
    {
      "id": 1,
      "name": "Anawak",
      "email": "[email protected]"
    }, {
      "id": 2,
      "name": "Tawantisuyu",
      "email": "[email protected]"
    }
  ]
}

:bug: Error ( if you want to see the log go on bottom :arrow_down: )

undefined method `id' for #<User::ActiveRecord_Relation:0x007f79602e0258>

image

:space_invader: Spec

  • Rails 4.2.5
  • DB: Postgresql 9.3
  • OS: Ubuntu 15.10 (Linux)

:page_facing_up: Files

_users_controller.rb_

module Api
  module V1
    class UsersController < BaseController
      skip_before_action :authenticate_user_from_token!

      # GET /api/v1/users
      def index
        @users = User.all
        render json: @users, serializer: UsersSerializer
      end
    end
  end
end

_users_serializer.rb_

module Api
  module V1
    class UsersSerializer < ActiveModel::Serializer
      attributes :status, :collection

      def status
        "ok"
      end

      def collection
        object.each do |item|
          UserSerializer.new(item)
        end
      end
    end
  end
end

_user_serializer.rb_

module Api
  module V1
    class UserSerializer < ActiveModel::Serializer
      attributes :id, :name, :email
    end
  end
end

:scroll: Log error

Started GET "/api/v1/users" for 127.0.0.1 at 2016-02-10 13:56:32 +0100
  ActiveRecord::SchemaMigration Load (0.5ms)  SELECT "schema_migrations".* FROM "schema_migrations"
Processing by Api::V1::UsersController#index as JSON
  User Load (0.9ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1  ORDER BY "users"."id" ASC LIMIT 1  [["id", 393]]
[active_model_serializers]   User Load (0.4ms)  SELECT "users".* FROM "users" WHERE "users"."visible" = $1
ORDER BY "users"."order_list" ASC  [["visible", "t"]]
[active_model_serializers] Rendered Api::V1::UserSerializer with ActiveModel::Serializer::Adapter::JsonApi (13.58ms)
Completed 500 Internal Server Error in 62ms (ActiveRecord: 7.3ms)

[Rollbar] Reporting exception: undefined method `id' for #<User::ActiveRecord_Relation:0x007f79602e0258>
[Rollbar] Exception not reported because Rollbar is disabled

NoMethodError - undefined method `id' for #<User::ActiveRecord_Relation:0x007f79602e0258>:
  activerecord (4.2.5) lib/active_record/relation/delegation.rb:136:in `method_missing'
  activerecord (4.2.5) lib/active_record/relation/delegation.rb:99:in `method_missing'
   () home/wakematta/.rvm/gems/ruby-2.2.2@myapp/bundler/gems/active_model_serializers-fb48bced5e45/lib/active_model/serializer/adapter/json_api/resource_identifier.rb
:34:in `id_for'
   () home/wakematta/.rvm/gems/ruby-2.2.2@myapp/bundler/gems/active_model_serializers-fb48bced5e45/lib/active_model/serializer/adapter/json_api/resource_identifier.rb
:7:in `initialize'
   () home/wakematta/.rvm/gems/ruby-2.2.2@myapp/bundler/gems/active_model_serializers-fb48bced5e45/lib/active_model/serializer/adapter/json_api.rb:103:in `process_res
ource'
   () home/wakematta/.rvm/gems/ruby-2.2.2@myapp/bundler/gems/active_model_serializers-fb48bced5e45/lib/active_model/serializer/adapter/json_api.rb:96:in `block in res
ource_objects_for'
   () home/wakematta/.rvm/gems/ruby-2.2.2@myapp/bundler/gems/active_model_serializers-fb48bced5e45/lib/active_model/serializer/adapter/json_api.rb:96:in `resource_obj

ects_for'
   () home/wakematta/.rvm/gems/ruby-2.2.2@myapp/bundler/gems/active_model_serializers-fb48bced5e45/lib/active_model/serializer/adapter/json_api.rb:60:in `serializable
_hash'
   () home/wakematta/.rvm/gems/ruby-2.2.2@myapp/bundler/gems/active_model_serializers-fb48bced5e45/lib/active_model/serializer/adapter/base.rb:22:in `as_json'
  activesupport (4.2.5) lib/active_support/json/encoding.rb:35:in `encode'
  activesupport (4.2.5) lib/active_support/json/encoding.rb:22:in `encode'
  activesupport (4.2.5) lib/active_support/core_ext/object/json.rb:37:in `to_json_with_active_support_encoder'
   () home/wakematta/.rvm/gems/ruby-2.2.2@myapp/bundler/gems/active_model_serializers-fb48bced5e45/lib/active_model/serializable_resource.rb:7:in `to_json'
   () home/wakematta/.rvm/gems/ruby-2.2.2@myapp/bundler/gems/active_model_serializers-fb48bced5e45/lib/active_model_serializers/logging.rb:69:in `block (3 levels) in
notify'
  activesupport (4.2.5) lib/active_support/callbacks.rb:117:in `call'
  activesupport (4.2.5) lib/active_support/callbacks.rb:555:in `block (2 levels) in compile'
  activesupport (4.2.5) lib/active_support/callbacks.rb:505:in `call'
  activesupport (4.2.5) lib/active_support/callbacks.rb:498:in `block (2 levels) in around'
  activesupport (4.2.5) lib/active_support/callbacks.rb:343:in `block (2 levels) in simple'
   () home/wakematta/.rvm/gems/ruby-2.2.2@myapp/bundler/gems/active_model_serializers-fb48bced5e45/lib/active_model_serializers/logging.rb:22:in `block (3 levels) in
instrument_rendering'
   () home/wakematta/.rvm/gems/ruby-2.2.2@myapp/bundler/gems/active_model_serializers-fb48bced5e45/lib/active_model_serializers/logging.rb:79:in `block in notify_rend
er'
  activesupport (4.2.5) lib/active_support/notifications.rb:164:in `block in instrument'
  activesupport (4.2.5) lib/active_support/notifications/instrumenter.rb:20:in `instrument'
  activesupport (4.2.5) lib/active_support/notifications.rb:164:in `instrument'
   () home/wakematta/.rvm/gems/ruby-2.2.2@myapp/bundler/gems/active_model_serializers-fb48bced5e45/lib/active_model_serializers/logging.rb:78:in `notify_render'
   () home/wakematta/.rvm/gems/ruby-2.2.2@myapp/bundler/gems/active_model_serializers-fb48bced5e45/lib/active_model_serializers/logging.rb:21:in `block (2 levels) in
instrument_rendering'
   () home/wakematta/.rvm/gems/ruby-2.2.2@myapp/bundler/gems/active_model_serializers-fb48bced5e45/lib/active_model_serializers/logging.rb:92:in `block in tag_logger'
  activesupport (4.2.5) lib/active_support/tagged_logging.rb:68:in `block in tagged'
  activesupport (4.2.5) lib/active_support/tagged_logging.rb:26:in `tagged'
  activesupport (4.2.5) lib/active_support/tagged_logging.rb:68:in `tagged'
   () home/wakematta/.rvm/gems/ruby-2.2.2@myapp/bundler/gems/active_model_serializers-fb48bced5e45/lib/active_model_serializers/logging.rb:92:in `tag_logger'

   () home/wakematta/.rvm/gems/ruby-2.2.2@myapp/bundler/gems/active_model_serializers-fb48bced5e45/lib/active_model_serializers/logging.rb:20:in `block in instrument_
rendering'
  activesupport (4.2.5) lib/active_support/callbacks.rb:441:in `block in make_lambda'
  activesupport (4.2.5) lib/active_support/callbacks.rb:342:in `block in simple'
  activesupport (4.2.5) lib/active_support/callbacks.rb:497:in `block in around'
  activesupport (4.2.5) lib/active_support/callbacks.rb:505:in `call'
  activesupport (4.2.5) lib/active_support/callbacks.rb:92:in `__run_callbacks__'
  activesupport (4.2.5) lib/active_support/callbacks.rb:778:in `_run_render_callbacks'
  activesupport (4.2.5) lib/active_support/callbacks.rb:81:in `run_callbacks'
   () home/wakematta/.rvm/gems/ruby-2.2.2@myapp/bundler/gems/active_model_serializers-fb48bced5e45/lib/active_model_serializers/logging.rb:68:in `block (2 levels) in
notify'
  actionpack (4.2.5) lib/action_controller/metal/renderers.rb:116:in `block in <module:Renderers>'
   () home/wakematta/.rvm/gems/ruby-2.2.2@myapp/bundler/gems/active_model_serializers-fb48bced5e45/lib/action_controller/serialization.rb:61:in `block (2 levels) in <
module:Serialization>'
  actionpack (4.2.5) lib/action_controller/metal/renderers.rb:45:in `block in _render_to_body_with_renderer'
  /home/wakematta/.rvm/rubies/ruby-2.2.2/lib/ruby/2.2.0/set.rb:283:in `each'
  actionpack (4.2.5) lib/action_controller/metal/renderers.rb:41:in `_render_to_body_with_renderer'
  actionpack (4.2.5) lib/action_controller/metal/renderers.rb:37:in `render_to_body'
  actionpack (4.2.5) lib/abstract_controller/rendering.rb:25:in `render'
  actionpack (4.2.5) lib/action_controller/metal/rendering.rb:16:in `render'
  actionpack (4.2.5) lib/action_controller/metal/instrumentation.rb:44:in `block (2 levels) in render'
  activesupport (4.2.5) lib/active_support/core_ext/benchmark.rb:12:in `block in ms'
  /home/wakematta/.rvm/rubies/ruby-2.2.2/lib/ruby/2.2.0/benchmark.rb:303:in `realtime'
  activesupport (4.2.5) lib/active_support/core_ext/benchmark.rb:12:in `ms'
  actionpack (4.2.5) lib/action_controller/metal/instrumentation.rb:44:in `block in render'
  actionpack (4.2.5) lib/action_controller/metal/instrumentation.rb:87:in `cleanup_view_runtime'
  activerecord (4.2.5) lib/active_record/railties/controller_runtime.rb:25:in `cleanup_view_runtime'
  actionpack (4.2.5) lib/action_controller/metal/instrumentation.rb:43:in `render'
  app/controllers/api/v1/users_controller.rb:18:in `index'
  actionpack (4.2.5) lib/action_controller/metal/implicit_render.rb:4:in `send_action'
  actionpack (4.2.5) lib/abstract_controller/base.rb:198:in `process_action'
  actionpack (4.2.5) lib/action_controller/metal/rendering.rb:10:in `process_action'
  actionpack (4.2.5) lib/abstract_controller/callbacks.rb:20:in `block in process_action'
  activesupport (4.2.5) lib/active_support/callbacks.rb:117:in `call'
  activesupport (4.2.5) lib/active_support/callbacks.rb:555:in `block (2 levels) in compile'

  activesupport (4.2.5) lib/active_support/callbacks.rb:505:in `call'
  activesupport (4.2.5) lib/active_support/callbacks.rb:92:in `__run_callbacks__'
  activesupport (4.2.5) lib/active_support/callbacks.rb:778:in `_run_process_action_callbacks'
  activesupport (4.2.5) lib/active_support/callbacks.rb:81:in `run_callbacks'
  actionpack (4.2.5) lib/abstract_controller/callbacks.rb:19:in `process_action'
  actionpack (4.2.5) lib/action_controller/metal/rescue.rb:29:in `process_action'
  actionpack (4.2.5) lib/action_controller/metal/instrumentation.rb:32:in `block in process_action'
  activesupport (4.2.5) lib/active_support/notifications.rb:164:in `block in instrument'
  activesupport (4.2.5) lib/active_support/notifications/instrumenter.rb:20:in `instrument'
  activesupport (4.2.5) lib/active_support/notifications.rb:164:in `instrument'
  actionpack (4.2.5) lib/action_controller/metal/instrumentation.rb:30:in `process_action'
  actionpack (4.2.5) lib/action_controller/metal/params_wrapper.rb:250:in `process_action'
  activerecord (4.2.5) lib/active_record/railties/controller_runtime.rb:18:in `process_action'
  actionpack (4.2.5) lib/abstract_controller/base.rb:137:in `process'
  actionview (4.2.5) lib/action_view/rendering.rb:30:in `process'
  actionpack (4.2.5) lib/action_controller/metal.rb:196:in `dispatch'
  actionpack (4.2.5) lib/action_controller/metal/rack_delegation.rb:13:in `dispatch'
  actionpack (4.2.5) lib/action_controller/metal.rb:237:in `block in action'
  actionpack (4.2.5) lib/action_dispatch/routing/route_set.rb:76:in `dispatch'
  actionpack (4.2.5) lib/action_dispatch/routing/route_set.rb:45:in `serve'
  actionpack (4.2.5) lib/action_dispatch/journey/router.rb:43:in `block in serve'
  actionpack (4.2.5) lib/action_dispatch/journey/router.rb:30:in `serve'
  actionpack (4.2.5) lib/action_dispatch/routing/route_set.rb:817:in `call'
  omniauth (1.3.1) lib/omniauth/strategy.rb:186:in `call!'
  omniauth (1.3.1) lib/omniauth/strategy.rb:186:in `call!'
  omniauth (1.3.1) lib/omniauth/strategy.rb:164:in `call'
  omniauth (1.3.1) lib/omniauth/strategy.rb:186:in `call!'
  omniauth (1.3.1) lib/omniauth/strategy.rb:164:in `call'
  omniauth (1.3.1) lib/omniauth/strategy.rb:186:in `call!'
  omniauth (1.3.1) lib/omniauth/strategy.rb:164:in `call'
  warden (1.2.4) lib/warden/manager.rb:35:in `block in call'
  warden (1.2.4) lib/warden/manager.rb:34:in `call'
  rack (1.6.4) lib/rack/etag.rb:24:in `call'
  rack (1.6.4) lib/rack/conditionalget.rb:25:in `call'

  rack (1.6.4) lib/rack/head.rb:13:in `call'
  actionpack (4.2.5) lib/action_dispatch/middleware/params_parser.rb:27:in `call'
  actionpack (4.2.5) lib/action_dispatch/middleware/flash.rb:260:in `call'
  rack (1.6.4) lib/rack/session/abstract/id.rb:225:in `context'
  rack (1.6.4) lib/rack/session/abstract/id.rb:220:in `call'
  actionpack (4.2.5) lib/action_dispatch/middleware/cookies.rb:560:in `call'
  activerecord (4.2.5) lib/active_record/query_cache.rb:36:in `call'
  activerecord (4.2.5) lib/active_record/connection_adapters/abstract/connection_pool.rb:653:in `call'
  activerecord (4.2.5) lib/active_record/migration.rb:377:in `call'
  actionpack (4.2.5) lib/action_dispatch/middleware/callbacks.rb:29:in `block in call'
  activesupport (4.2.5) lib/active_support/callbacks.rb:88:in `__run_callbacks__'
  activesupport (4.2.5) lib/active_support/callbacks.rb:778:in `_run_call_callbacks'
  activesupport (4.2.5) lib/active_support/callbacks.rb:81:in `run_callbacks'
  actionpack (4.2.5) lib/action_dispatch/middleware/callbacks.rb:27:in `call'
  actionpack (4.2.5) lib/action_dispatch/middleware/reloader.rb:73:in `call'
  actionpack (4.2.5) lib/action_dispatch/middleware/remote_ip.rb:78:in `call'
  rollbar (2.7.1) lib/rollbar/middleware/rails/rollbar.rb:24:in `block in call'
  rollbar (2.7.1) lib/rollbar.rb:854:in `scoped'
  rollbar (2.7.1) lib/rollbar/middleware/rails/rollbar.rb:22:in `call'
  better_errors (2.1.1) lib/better_errors/middleware.rb:84:in `protected_app_call'
  better_errors (2.1.1) lib/better_errors/middleware.rb:79:in `better_errors_call'
  better_errors (2.1.1) lib/better_errors/middleware.rb:57:in `call'
  actionpack (4.2.5) lib/action_dispatch/middleware/debug_exceptions.rb:17:in `call'
  rollbar (2.7.1) lib/rollbar/middleware/rails/show_exceptions.rb:22:in `call_with_rollbar'
  web-console (2.2.1) lib/web_console/middleware.rb:39:in `call'
  actionpack (4.2.5) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
  railties (4.2.5) lib/rails/rack/logger.rb:38:in `call_app'
  railties (4.2.5) lib/rails/rack/logger.rb:20:in `block in call'
  activesupport (4.2.5) lib/active_support/tagged_logging.rb:68:in `block in tagged'
  activesupport (4.2.5) lib/active_support/tagged_logging.rb:26:in `tagged'
  activesupport (4.2.5) lib/active_support/tagged_logging.rb:68:in `tagged'
  railties (4.2.5) lib/rails/rack/logger.rb:20:in `call'
  quiet_assets (1.1.0) lib/quiet_assets.rb:27:in `call_with_quiet_assets'
  actionpack (4.2.5) lib/action_dispatch/middleware/request_id.rb:21:in `call'
  rack (1.6.4) lib/rack/methodoverride.rb:22:in `call'
  rack (1.6.4) lib/rack/runtime.rb:18:in `call'
  activesupport (4.2.5) lib/active_support/cache/strategy/local_cache_middleware.rb:28:in `call'
  rack (1.6.4) lib/rack/lock.rb:17:in `call'
  actionpack (4.2.5) lib/action_dispatch/middleware/static.rb:116:in `call'
  rack (1.6.4) lib/rack/sendfile.rb:113:in `call'
  railties (4.2.5) lib/rails/engine.rb:518:in `call'
  railties (4.2.5) lib/rails/application.rb:165:in `call'
  rack (1.6.4) lib/rack/content_length.rb:15:in `call'
  puma (2.15.3) lib/puma/server.rb:541:in `handle_request'
  puma (2.15.3) lib/puma/server.rb:388:in `process_client'
  puma (2.15.3) lib/puma/server.rb:270:in `block in run'
  puma (2.15.3) lib/puma/thread_pool.rb:106:in `block in spawn_thread'

Started POST "/__better_errors/d384386d2c6afc56/variables" for 127.0.0.1 at 2016-02-10 13:56:33 +0100
Question Needs Submitter Response 0.10.x

Most helpful comment

+1. Issue exists

All 8 comments

would you mind upgrading to rc4 and using the block form for collection?

Thanks for the report. :+1:

I think the bug has to do with an atypical usage of serializers.

      def collection
        object.each do |item|
          UserSerializer.new(item)
        end
      end

isn't recommended, and probably should be map

typo: The controller example code is the serializer :)

The example code you're using isn't the normal naming schema for this sort of serialization.

Normally, you'd render json: @users, serializer: Api::V1::UserSerializer and using the default CollectionSerializer. If you wanted your own custom collection serializer for users, then you would indeed pass each_serializer: Api::V1::UserSerializer, serializer: Api::V1::UsersSerializer, making sure to implement the CollectionSerializer interface of responding to each and yielding the serializer.

I assume this is the Json adapter?

I tried map but dont work, the same problem.

This is my solution:

_users_controller.rb_

module Api
  module V1
    class UsersController < BaseController
      skip_before_action :authenticate_user_from_token!

      # GET /api/v1/users
      def index
        @users = User.all

        # This is my solution:
        render json: @users, each_serializer: UserSerializer, 
          serializer: ActiveModel::Serializer::CollectionSerializer
      end
    end
  end
end

_config/initializers/active_model_serializers.rb_

ActiveModelSerializers.config.adapter = ActiveModel::Serializer::Adapter::JsonApi

Hi have an other question.

How i need to use has_many with adapter Json API

This is my code:

module Api
  module V1
    class CharacterSerializer < ActiveModel::Serializer
      attributes :id, :name, :background, :xp, :xp_required, :image_url,
                 :avatar_url, :gender, :kind

      has_many :friends
    end
  end
end

This is the result:

{
  "data": {
    "id": "503",
    "type": "user",
    "attributes": {
      "name": "Jhon",
      "email": "[email protected]",
    },
    "relationships": {
      "friends": {
        "data": [
          {
            "id": "33",
            "type": "friends"
          },
          {
            "id": "6",
            "type": "friends"
          }
        ]
      }
    }
  }
}

But i want this result:

{
  "data": {
    "id": "503",
    "type": "user",
    "attributes": {
      "name": "Jhon",
      "email": "[email protected]",
    },
    "relationships": {
      "friends": {
        "data": [
          {
            "id": "33",
            "type": "friends",
            "data": {
              "name": "Ana",
              "name": "[email protected]"
            }
          },
          {
            "id": "6",
            "type": "friends",
            "data": {
              "name": "Rambo",
              "name": "[email protected]"
            }
          }
        ]
      }
    }
  }
}

I guess you could use the block form or customize the adapter. What's your need.

B mobile phone

On Feb 11, 2016, at 7:10 AM, Mohamed Ziata [email protected] wrote:

Hi have an other question.

How i need to use has_many with adapter Json API

This is my code:

module Api
module V1
class CharacterSerializer < ActiveModel::Serializer
attributes :id, :name, :background, :xp, :xp_required, :image_url,
:avatar_url, :gender, :kind#, :skills, :traits

  has_many :friends
end

end
end
This is the resultation:

{
"data": {
"id": "503",
"type": "user",
"attributes": {
"name": "Jhon",
"email": "[email protected]",
},
"relationships": {
"friends": {
"data": [
{
"id": "33",
"type": "friends"
},
{
"id": "6",
"type": "friends"
}
]
}
}
}
}
But i want this result:

{
"data": {
"id": "503",
"type": "user",
"attributes": {
"name": "Jhon",
"email": "[email protected]",
},
"relationships": {
"friends": {
"data": [
{
"id": "33",
"type": "friends",
"data": {
"name": "Ana",
"name": "[email protected]"
}
},
{
"id": "6",
"type": "friends",
"data": {
"name": "Rambo",
"name": "[email protected]"
}
}
]
}
}
}
}
—
Reply to this email directly or view it on GitHub.

Closing due to lack of response from the submitter. We'll re-open if this is still an issue.

I'm looking for the exact same thing.
I've tried to achieve the same result in many ways, but without any luck so far.

What is the cleanest approach, while still keeping the default json_api adapter?

+1. Issue exists

Only solution I have seen is using ActiveModel::ArraySerializer

    claims = @employee_form.claims.claim_status_order
    claims = ActiveModel::ArraySerializer.new(
      @employee_form.claims.claim_status_order,
      each_serializer: ClaimSerializer,
    ).serializable_array
    render json: claims, status: :ok
Was this page helpful?
0 / 5 - 0 ratings

Related issues

AlexCppns picture AlexCppns  Â·  5Comments

JohnMerlino2 picture JohnMerlino2  Â·  3Comments

kapso picture kapso  Â·  4Comments

Mifrill picture Mifrill  Â·  4Comments

Andriykoo picture Andriykoo  Â·  5Comments