我有两个模型,其中A has_many B.如果我加载A包括相关的B:
a = A.find(:first, include: :bs)
a.inspect
仅显示a:
=> "#<A id: 1, name: \"Test\", created_at: \"2012-07-02 21:50:32\", updated_at: \"2012-07-02 21:50:32\">"
如何a.inspect
显示所有关联的a.bs
?
答案 0 :(得分:1)
默认情况下,您无法执行此操作。检查对象可能会产生太多问题和副作用。但是,您可以使用以下内容扩展inspect
:
class A < ActiveRecord::Base
...
def inspect
[super, bs.inspect].join("\n")
end
end
请注意,这并不是很聪明,因为每次检查bs
实例时都会强制加载A
。所以也许你想变得更聪明并做这样的事情:
def inspect
[super, bs.loaded? ? bs.inspect : nil].compact.join("\n")
end
这只会检查bs
是否已预先加载(例如:include
)。
或许你想创建一个super_inspect
而不是自动完成所有事情。您可以使用以下内容扩展ActiveRecord::Base
class ActiveRecord::Base
def deep_inspect
([inspect] + self.class.reflect_on_all_associations.map { |a|
self.send(a.name).inspect
}).compact.join("\n ")
end
end
这将自动查找与reflect_on_all_associations
的所有关联,如果关联已加载,则会在其上调用inspect
。
现在您可以修改上面的代码,但是您想要创建自己的自定义检查,或者只是根据需要扩展当前检查。用一点代码可以做任何事情。
以下是更智能的更新版本的示例:
class ActiveRecord::Base
def deep_inspect
([inspect] + self.class.reflect_on_all_associations.map { |a|
out = ""
assoc = self.send(a.name)
# Check for collection
if assoc.is_a?(ActiveRecord::Associations::CollectionProxy)
# Include name of collection in output
out += "\n#{assoc.name.pluralize}:\n"
out += self.send(a.name).to_a.inspect
else
out += self.send(a.name).inspect
end
out
}).compact.join("\n ")
end
end
答案 1 :(得分:0)
与@Casper的答案相同,这是一个帮助程序方法,用于封存依赖关系链下的所有关联:
# 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 a
这与检查并不完全相同,因为它实际上是将对象序列化为哈希结构,但是它将为您提供类似的信息。
请注意,可能的关联被分为两组:单一关联(引用单个目标对象)和多个关联(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