Home > Back-end >  ActiveModel::Serializers JSON API nested associations needs to include a value
ActiveModel::Serializers JSON API nested associations needs to include a value

Time:08-12

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"
                    }
                }
            }
        }

CodePudding user response:

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.

  • Related