... SO
我正在编写一些代码,用于查询带有关联的活动记录,并以类似于...的格式返回数据。
[{
foo: {
id: ...,
foo_property: ...
},
bar: {
id: ...,
bar_property: ...
}
}, ...]
...顶级活动记录及其关联都有时间戳和我想排除的其他字段。我知道attributes
和as_json
,但这两个都不遵循关系(而是用foo_id和bar_id替换foo和bar)。我也知道AssociationReflection
及其动态查找关联的能力,这些关联可以通过某些复杂性执行我想要的,但理想情况下......
我想用一种简单,优雅的方式通过这种转换和属性过滤来查询我的数据,即
Whatever.joins(:foos, :bars)
.eager_load(:foos, :bars)
.? # convert results to an array of hashes with association data (under appropriately named hash key)
.? # filter top level entries and association data to not have timestamps, etc. (select?)
...谢谢!
答案 0 :(得分:2)
我建议使用支持关联的ActiveModel::Serializers:
class WhateverSerializer < ApplicationSerializer
attributes :id, :other_attribute, :third_attribute
has_many :foos
has_many :bars
end
这允许您在最终的JSON输出中指定所需的属性(通过attributes
)并让您整合关联(他们将分别使用FooSerializer
和BarSerializer
)。
在相应的控制器中,您只需使用
即可render json: whatever
并且对象将由序列化程序自动包装。或者,如果您有一组Whatever
个对象,则可以执行以下操作:
render json: Whatever.all, each_serializer: WhateverSerializer
答案 1 :(得分:0)
您可以使用以下语法实现相同的行为:
假设嵌套关联如:baz有很多:bars和:bar有很多:foos
render json: Foo.includes(bar: :baz),
include: {bar: {include: {baz: {only: [:attr_a]}},
only: [:attr_b]}}, only: [:attr_1, :attr_2, :attr_3]
但我也建议使用ActiveModel::Serializers。当你有很多关联时,这种语法就不清楚了。
答案 2 :(得分:0)
您可以尝试deep_pluck
Whatever.deep_pluck(
foo: [:id, :foo_property, ...],
bar: [:id, :bar_property, ...],
)
答案 3 :(得分:0)
该问题的其他答案为序列化已知关联提供了简洁的解决方案,以下是一个综合工具,可对任何对象序列化整个基于关联的依赖关系图,而无需专门枚举每个所需的关联:
[这是我对“ Inspect object with associations”给出的答案的转贴]
# app/models/application_record.rb
#
# placing the helper in the ApplicationRecord superclass
# allows all application models to inherit the helper
class ApplicationRecord < ActiveRecord::Base
def self.marshal
# collect the names of the objects associations
single_associations = self.class.reflect_on_all_associations(:has_one ).map {|x| x.name}
plural_associations = self.class.reflect_on_all_associations(:has_many).map {|x| x.name}
# serialize the object as a JSON-compatible hash
self.as_json.merge(
# merge in a hash containing each `has_one` association via recursive marshalling
# the resulting set of associated objects are merged into
# the original object's serialized hash, each keyed by the name of the association
single_associations.reduce({}) { |memo, assoc| memo.merge({ assoc => self.send(assoc).marshal }) }.as_json
).merge(
# merge in the `has_many` associations
# the resulting set of associated collections must then be processed
# via mapping each collection into an array of singular serialized objects
plural_associations.reduce({}) { |memo, assoc| memo.merge({ assoc => self.send(assoc).map {|item| item.marshal } }) }.as_json
)
end
end
然后您可以通过调用以下方法来调用此帮助方法:
Marshal.serialize whatever
这与检查并不完全相同,因为它实际上是将对象序列化为哈希结构,但是它将为您提供类似的信息。
请注意,可能的关联被分为两组:单一关联(引用单个目标对象)和多个关联(ActiveRecord CollectionProxy对象,即它们是可枚举的)。因为我们将关联的对象序列化为散列,所以每个has_many
关联都必须解析为单个序列化对象的集合(例如,我们将集合内的每个关联映射为其序列化形式)。
belongs_to
关联应该被忽略,因为在两个方向上的映射关联都将立即创建一个循环依赖图。如果您想沿“归属链”封送,则可以执行类似的操作
def self.trace
parent_associations = obj.class.reflect_on_all_associations(:belongs_to).map {|x| x.name}
obj.as_json.merge single_associations.reduce({}) { |memo, assoc| memo.merge({ assoc => obj.send(assoc).trace }) }.as_json
end