动态包含 Rails 中对象的关联
Dynamically include associations for objects in Rails
我目前正在开发一个小型 Rails 5 应用程序,我需要根据某些事件将 ActiveRecord 对象传递给外部服务。在我的模型中,我定义了以下内容:
# /models/user.rb
after_create :notify_external_service_of_user_creation
def notify_external_service_of_user_creation
EventHandler.new(
event_kind: :create_user,
content: self
)
end
EventHandler
然后将此对象转换为 JSON 并通过 HTTP 请求将其发送到外部服务。通过在对象上调用 .to_json
这会呈现一个 JSON 输出,看起来像这样:
{
"id":1234,
"email":"test@testemail.dk",
"first_name":"Thomas",
"last_name":"Anderson",
"association_id":12,
"another_association_id":356
}
现在,我需要一种方法将所有一级关联直接包含到其中,而不是只显示 foreign_key。所以我正在寻找的结构是这样的:
{
"id":1234,
"email":"test@testemail.dk",
"first_name":"Thomas",
"last_name":"Anderson",
"association_id":{
"attr1":"some_data",
"attr2":"another_value"
},
"another_association_id":{
"attr1":"some_data",
"attr2":"another_value"
},
}
我的第一个想法是像这样反思模型:object.class.name.constantize.reflect_on_all_associations.map(&:name)
,在这种情况下 object
是用户的一个实例,并使用此列表遍历关联并包括他们在输出中。虽然这看起来很乏味,所以我想知道是否有更好的方法使用 Ruby 2.4 和 Rails 5.
来实现这一点
如果您不想使用外部序列化器,您可以为每个模型覆盖 as_json
。 as_json
被 to_json
调用。
module JsonWithAssociations
def as_json
json_hash = super
self.class.reflect_on_all_associations.map(&:name).each do |assoc_name|
assoc_hash = if send(assoc_name).respond_to?(:first)
send(assoc_name).try(:map, &:as_json) || []
else
send(assoc_name).as_json
end
json_hash.merge!(assoc_name.to_s => assoc_hash)
end
json_hash
end
end
您需要 prepend
这个特定的模块,以便它覆盖默认的 as_json
方法。
User.prepend(JsonWithAssociations)
或
class User
prepend JsonWithAssociations
end
我目前正在开发一个小型 Rails 5 应用程序,我需要根据某些事件将 ActiveRecord 对象传递给外部服务。在我的模型中,我定义了以下内容:
# /models/user.rb
after_create :notify_external_service_of_user_creation
def notify_external_service_of_user_creation
EventHandler.new(
event_kind: :create_user,
content: self
)
end
EventHandler
然后将此对象转换为 JSON 并通过 HTTP 请求将其发送到外部服务。通过在对象上调用 .to_json
这会呈现一个 JSON 输出,看起来像这样:
{
"id":1234,
"email":"test@testemail.dk",
"first_name":"Thomas",
"last_name":"Anderson",
"association_id":12,
"another_association_id":356
}
现在,我需要一种方法将所有一级关联直接包含到其中,而不是只显示 foreign_key。所以我正在寻找的结构是这样的:
{
"id":1234,
"email":"test@testemail.dk",
"first_name":"Thomas",
"last_name":"Anderson",
"association_id":{
"attr1":"some_data",
"attr2":"another_value"
},
"another_association_id":{
"attr1":"some_data",
"attr2":"another_value"
},
}
我的第一个想法是像这样反思模型:object.class.name.constantize.reflect_on_all_associations.map(&:name)
,在这种情况下 object
是用户的一个实例,并使用此列表遍历关联并包括他们在输出中。虽然这看起来很乏味,所以我想知道是否有更好的方法使用 Ruby 2.4 和 Rails 5.
如果您不想使用外部序列化器,您可以为每个模型覆盖 as_json
。 as_json
被 to_json
调用。
module JsonWithAssociations
def as_json
json_hash = super
self.class.reflect_on_all_associations.map(&:name).each do |assoc_name|
assoc_hash = if send(assoc_name).respond_to?(:first)
send(assoc_name).try(:map, &:as_json) || []
else
send(assoc_name).as_json
end
json_hash.merge!(assoc_name.to_s => assoc_hash)
end
json_hash
end
end
您需要 prepend
这个特定的模块,以便它覆盖默认的 as_json
方法。
User.prepend(JsonWithAssociations)
或
class User
prepend JsonWithAssociations
end