ruby-on-railsrubyactive-model-serializersfastjsonapi

jsonapi::Serializer Specify Foreign Key in Association belongs_to / has_many


I have a database that I cannot modify as it is a read-only populated from a node I don't control.

This causes the tables to have foreign_keys that are different from the Rails default way. You can see the current situation in the models below:

# app/models/epoch_stake.rb
class EpochStake < DbSyncRecord
    self.table_name = 'epoch_stake'
    belongs_to :stake_address, foreign_key: :addr_id
end

# app/models/stake_address.rb
class StakeAddress < DbSyncRecord
    self.table_name = "stake_address"
    has_many :epoch_stakes, foreign_key: :addr_id
end

addr_id rather than stake_address_id

Now I am creating a controller to fetch one of the model, using a serializer to show the associated model.

class EpochStakeController < ApplicationController
    def index
        epoch_stakes = EpochStake.all
        render json: EpochStakeSerializer.new(epoch_stakes)
    end
end

It seems though that when I try to tell the JSONAPI::Serializer to be aware of the different foreign_key, that doesn't get taken into account:

# app/serializers/epoch_stake_serializers.rb
class EpochStakeSerializer
  include JSONAPI::Serializer
  attributes :epoch_no, :amount
  belongs_to :stake_address, foreign_key: :addr_id
end

Infact when I query the controller (/epoch_stakes) with the configuration above I receive the following error, as if the serializer is trying to look for the association with the Rails default foreign_key rather than the one I specified in the serializer:

NoMethodError: undefined method `stake_address_id' for #<EpochStake:0x00007fcf9f22ad50>
Did you mean?  stake_address
               stake_address=
from /Users/sergio/.rvm/gems/ruby-2.6.1/gems/activemodel-6.1.3/lib/active_model/attribute_methods.rb:469:in `method_missing'

How can I make the serializer aware of the different foreign_key?


Solution

  • You should use the id_method_name option:

    # app/serializers/epoch_stake_serializers.rb
    class EpochStakeSerializer
      include JSONAPI::Serializer
      attributes :epoch_no, :amount
      belongs_to :stake_address, id_method_name: :addr_id
    end
    

    See documentation: https://github.com/jsonapi-serializer/jsonapi-serializer#customizable-options