0

呈現我的問題的假想簡化版本。想象一下,我有一個網站,用戶可以用自己的品牌創建一個商店,並從產品目錄中選擇要顯示在他們的商店。商店&產品有一個擁有和屬於多(HABTM)的關係。每種產品都有自己的特定商店路線。訪問ActiveModelSerializers中Child序列化程序中的父對象

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

不幸的是,串行器關聯似乎沒有提供一種乾淨的方式將自定義屬性傳遞給子序列化器。雖然有一些不那麼漂亮的解決方案。

1.激活ProductSerializer手動,在ShopSerializer

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.添加店鋪ID的Product實例添加URL它們被饋送到ProductSerializer

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 
之前

這兩個解決方案tions應該是線程安全的,但第一種解決方案對我來說似乎是一個更好的主意,因爲第二種解決方案使ProductSerializer自己無法使用—,即當只有一個Product在不知道它應該屬於的特定商店的情況下被串行化。

+0

解決方案#1偉大的工作(沒有嘗試#2),只是我不得不打電話'Rails.application.routes.url_helpers.shop_product_url'否則我'NoMethodError(未定義的方法 'shop_product_url' 爲#<::加載ActiveModel Serializer :: HasManyReflection:0x007fde59072670>)(甚至在串行器中包含Rails.application.routes.url_helpers) – swrobel

+1

我敢打賭,block是'instance_eval'ed,這就是爲什麼它不能訪問包含的幫助器。您可以嘗試在頂部使用'url_helpers = Rails.application.routes.url_helpers',並在模塊內部使用'url_helpers.shop_product_url(...)',以獲得更乾淨的解決方案。 –

+0

不幸的是,這實際上並不是線程安全的。我希望我對此有一些很好的見解,但實質上問題是,如果在不同商店的不同Puma線程上同時發出兩個請求,第二個請求將使用第一個'object.id'又名'Shop#id' 。我無法寫出失敗的測試,但我在生產中可靠地看到它。尚未測試第二個解決方案... – swrobel