在 ActiveModelSerializers 的子序列化器中访问父对象

Accessing Parent object in Child serializer in ActiveModelSerializers

提出我的问题的一个假设的简化版本。假设我有一个网站,用户可以在其中创建带有自己品牌的商店,并从产品目录中选择要在他们的商店中展示的产品。 Shops & Products 具有拥有和属于许多 (HABTM) 的关系。每个产品都有自己的商店特定路线。

Rails.application.routes.draw do
  resources :shops do
    resources :products
  end
end

class ShopSerializer < ActiveModel::Serializer
  has_many :products
end

class ProductSerializer < ActiveModel::Serializer
  include Rails.application.routes.url_helpers

  attribute :url do
    shop_product_url(NEED SHOP ID, product_id: object.id)
  end  
end

当商店被序列化时,其产品的集合也被序列化,我希望产品序列化器知道正在对其进行序列化的商店,并使用它在序列化输出中包含路由.这怎么可能?我已经尝试了从 ShopSerializer 传递 instance_options 的所有方式,但它没有按预期工作。

# this works except is apparently not threadsafe as multiple
# concurrent requests lead to the wrong shop_id being used
# in some of the serialized data
has_many :products do
  ActiveModelSerializers::SerializableResource.new(shop_id: object.id).serializable_hash
end

# shop_id isn't actually available in instance_options
has_many :products do
  ProductSerializer.new(shop_id: object.id)
end

不幸的是,序列化器关联似乎没有提供将自定义属性传递给子序列化器的简洁方法。虽然有一些不太漂亮的解决方案。

1.手动调用ProductSerializer,在ShopSerializer

中添加URL
class ProductSerializer < ActiveModel::Serializer
end

class ShopSerializer < ActiveModel::Serializer
  include Rails.application.routes.url_helpers

  attribute :products do
    object.products.map do |product|
      ProductSerializer.new(product).serializable_hash.merge(
        url: shop_product_url(object.id, product_id: product.id)
      )
    end
  end
end

2。在将 Product 个实例提供给 ProductSerializer

之前,将商店 ID 添加到 Product 个实例
class ProductSerializer < ActiveModel::Serializer
  include Rails.application.routes.url_helpers

  attribute :url do
    shop_product_url(object.shop_id, product_id: object.id)
  end 
end

class ShopSerializer < ActiveModel::Serializer
  has_many :products, serializer: ProductSerializer do
    shop = object
    shop.products.map do |product|
      product.dup.tap do |instance|
        instance.singleton_class.send :define_method, :shop_id do
          shop.id
        end
      end
    end
  end
end

两种解决方案都应该是线程安全的,但第一个解决方案对我来说似乎是一个更好的主意,因为第二个解决方案使 ProductSerializer 无法单独使用——即当只有一个 Product 是在不知道它应该属于哪个特定商店的情况下进行了序列化。