0

私の問題の単純化された仮説を提示する。ユーザーが自分のブランドでショップを作成し、そのショップで表示する商品のカタログから選択できるウェブサイトがあるとします。ショップ&製品には、HABTM(has-and-belong-to-many)関係があります。各製品には、独自のショップ固有のルートがあります。ActiveModelSerializersの子シリアライザの親オブジェクトへのアクセス

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手動で、彼らは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 
に供給される前 Productインスタンスに 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にURLを追加

両方のsolu第2の方法は、をそれ自身の—で使用できないようにする、つまりただ1つのProductが所属する特定のショップを知らずにシリアライズされるとき、最初の解決策は私にとってより良い考えのように思えます。

+0

私は 'Rails.application.routes.url_helpers.shop_product_url'を呼び出さなければならなかった点を除いて、#2は試したことがありませんでした。それ以外の場合は、NoMethodErrorを取得しました(#) '(たとえ'シリアライザの 'Rails.application.routes.url_helpers'を含んでいても) – swrobel

+1

ブロックが' instance_eval'されていると思いますので、それが含まれているヘルパーにアクセスできません。上部には 'url_helpers = Rails.application.routes.url.hell_helpers'、ブロックの内側には' url_helpers.shop_product_url(...) 'を試してみてください。 –

+0

残念ながら、これは実際にはスレッドセーフではないようです。なぜか、私はいくつかの良い洞察をしたいと思うが、本質的に問題は、異なる店舗の異なるPumaスレッドに2つの同時リクエストがある場合、2番目のリクエストは最初の 'object.id' aka' Shop#id' 。私は失敗したテストを書くことができませんでしたが、私はそれを生産において確実に見ています。まだ2番目のソリューションをテストしていない... – swrobel

関連する問題