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

时间:2017-07-08 17:41:32

标签: ruby-on-rails ruby-on-rails-5 active-model-serializers

提出我的问题的假设,简化版本。想象一下,我有一个网站,用户可以用自己的品牌创建一个商店,并从商店目录中选择要在他们的商店展示。商店&a​​mp;产品具有“属于多”(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

当Shop被序列化时,其产品的集合也是如此,我希望Product serializer知道正在序列化它的商店并使用它来在序列化输出中包含该路由。这怎么可能?我尝试过从instance_options传递ShopSerializer的所有方式,但它没有按预期工作。

# 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 个答案:

答案 0 :(得分:1)

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

<强> 1。手动调用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

中添加网址
Product

<强> 2。将商店ID添加到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

ProductSerializer

这两个解决方案都应该是线程安全的,但第一个解决方案对我来说似乎更好,因为第二个解决方案使Product无法自行使用 - 即只有一个skip_if_no_db <- function() { if (db_conn()) { skip("API not available") } } test_that("foo api returns bar when given baz", { skip_if_no_db() ... }) 被序列化而没有了解它应该属于的特定商店。

相关问题