ActiveModel::Serializers JSON API nested associations needs to include a value

657 Views Asked by At

I have an Rails 7 API and i'm using gem 'active_model_serializers', '~> 0.10.0' to make het fit in the json_api requirements, but i need to in the nested attributes of my items include the name, not only the id and type, i tried many things i found in the internet, but none of them solved this for my, and i'm hoping someone here could.

my products_controller.rb

class ProductsController < ApplicationController

  include ActionController::HttpAuthentication::Token::ControllerMethods
  before_action :authenticate

  include ErrorSerializer

  before_action :set_product, only: %i[ show update destroy ]

  # GET /products
  def index
    page_number = params[:page].try(:[], :number)
    per_page = params[:page].try(:[], :size)


    @products = Product.all.page(page_number).per(per_page)

    # paginate json: @products
    render json: @products, show_category: (param? params[:category]), show_unit: (param? params[:unit])
  end

  def all
    @products = Product.all

    render json: @products
  end

  # GET /products/1
  def show
    render json: @product
  end

#The rest of crud options

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_product
      @product = Product.find(params[:id])
    end

    # Only allow a list of trusted parameters through.
    def product_params
      params.require(:product).permit(:name, :description, :quantity_in_stock, :price, :highlight, :category_id, :unit_id)
    end

    def authenticate
      authenticate_or_request_with_http_token do |token, options|
        hmac_secret = ENV['TOKEN']
        JWT.decode token, hmac_secret, true, { :algorithm => 'HS256' }
      end
    end
end

my product_serializer

class ProductSerializer < ActiveModel::Serializer
  attributes :id, :name, :description, :quantity_in_stock, :price, :highlight
  
  belongs_to :category, optional: true
  belongs_to :unit, optional: true

  def should_render_category
    @instance_options[:show_category]
  end
  def should_render_unit
    @instance_options[:show_unit]
  end
end

my unit_serializer:

class UnitSerializer < ActiveModel::Serializer
  attributes :id, :name

  has_many :products, optional: true
end

my category_serializer:

class CategorySerializer < ActiveModel::Serializer
  attributes :id, :name

  has_many :products, optional: true
end

and my application_controller:

class ApplicationController < ActionController::API
  before_action :ensure_json_request

  def param? param

    param && param != "false" && param != "nil"
  
  end

  def ensure_json_request
    unless request.headers["Accept"] =~ /vnd\.api\+json/
      render body: nil, :status => 406
    else
      unless request.get?
        return if request.headers["Content-Type"] =~ /vnd\.api\+json/
        render body: nil, :status => 415
      end
    end
  end
end

And my actual response:

{
            "id": "1",
            "type": "products",
            "attributes": {
                "name": "Lightweight Iron Keyboard",
                "description": "Sit quas ipsa. Animi non omnis. Eveniet et quidem.",
                "quantity-in-stock": 99,
                "price": 27.88,
                "highlight": false
            },
            "relationships": {
                "category": {
                    "data": {
                        "id": "4",
                        "type": "categories"
                    }
                },
                "unit": {
                    "data": {
                        "id": "2",
                        "type": "units"
                    }
                }
            }
        }
1

There are 1 best solutions below

1
zhisme On BEST ANSWER

As mentioned by comments, you should look for alternatives as this gem is no longer maintained

Regarding your question, docs says about specifying serializer So to modify:

class ProductSerializer < ActiveModel::Serializer
  # ...
  
  belongs_to :category, optional: true, serializer: MyCategorySerializer
  # ...
class MyCategorySerializer < ActiveModel::Serializer
  attributes :id, :name, :type
end

and do the same way for UnitSerializer it should work smoothly.