提出我的问题的假设,简化版本。想象一下,我有一个网站,用户可以用自己的品牌创建一个商店,并从商店目录中选择要在他们的商店展示。商店&产品具有“属于多”(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
答案 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()
...
})
被序列化而没有了解它应该属于的特定商店。