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

How to format associations to exclude root element? #2426

Open
sarah-mica opened this issue Aug 4, 2021 · 2 comments
Open

How to format associations to exclude root element? #2426

sarah-mica opened this issue Aug 4, 2021 · 2 comments

Comments

@sarah-mica
Copy link

sarah-mica commented Aug 4, 2021

I'm using ActiveModel::Serializer to format my model data as json, but I would like to change the formatting so that the associations of my main model are not nested. I tried setting root: false and that doesn't work

Expected behavior vs actual behavior

I have a model Account with an association belongs_to :account_status
and I was able to add this association in the AccountSerializer to get that associated data just fine. But due to my api contract requirements, I need the json to be formatted without the association nesting.

So I'm getting this:

{
   "account_id": 1
   <other account info>
   ...
   "account_status": {
      "status_code": 1
      "desc": "status description"
      ....
   }
}

But I want this:

{
   "account_id": 1
   <other account info>
   ...
   "account_status_status_code": 1
   "account_status_desc": "status description"
   ....
}

Model + Serializer code

How can I achieve the expected behavior without writing each account_status field as an individual attribute in the AccountSerializer ??

Controller

class AccountsController < ActionController::API
  def show
    account = Account.find(params[:account_id])
    render json: account
  end
end

Model

class Account < ActiveRecord::Base
  self.primary_key = :account_id

  belongs_to :account_status, foreign_key: :account_status_code, inverse_of: :accounts

  validates :account_status_code, presence: true
end

Serializer

class AccountSerializer < ActiveModel::Serializer
  attributes(*Account.attribute_names.map(&:to_sym))

  belongs_to :account_status, 
             foreign_key: :account_status_code,
             inverse_of: :accounts
end

Environment

ActiveModelSerializers Version 0.10.0:

Output of ruby -e "puts RUBY_DESCRIPTION":
ruby 3.0.2p107 (2021-07-07 revision 0db68f0233) [x86_64-darwin19]

OS Type & Version: macOS Catalina v 10.15.7

Integrated application and version Rails 6.1.4:

@wasifhossain
Copy link
Member

wasifhossain commented Aug 5, 2021

as it looks, your expected structure does NOT match any of the available adapters (attributes/json/json-api).

so you have to DIY, by defining the association fields at the top-level serializer like this:

class AccountSerializer < ActiveModel::Serializer
  attributes :account_id, :account_status_status_code, :account_status_desc

  def account_status_status_code
    object.status_code
  end

  def account_status_desc
    object.desc
  end
end

DOC: https://github.com/rails-api/active_model_serializers/blob/0-10-stable/docs/general/serializers.md#attributes-1

@sarah-mica
Copy link
Author

Thanks for verifying @wasifhossain. I knew this was an option but I wanted to avoid manually defining each association's trait manually if there was a better way.

I know the json structure is not standard. Unfortunately I'm making an api port from a legacy system so I can't change the contract at this time.

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