return 具有关联的 ActiveRecord 对象的干净方式
Clean way to return ActiveRecord object with associations
我想 return 所有只有关联的事物模型对象没有 asscoiation_id
,有没有更好的方法来做到这一点没有 include
和 except
?
# Thing.rb
belongs_to :object_a
belongs_to :object_b
# create_thing.rb
def change
create_table :things, id: false do |t|
t.string :id, limit: 36, primary_key: true
t.string :object_a_id, foreign_key: true
t.string :object_b_id, foreign_key: true
t.timestamps
end
end
# things_controller.rb
render json: Thing.all, include: [:object_a, :object_b]
output => {
id: ....
object_a_id: 'object_a_id',
object_b_id: 'object_b_id',
object_a: {
id: object_a_id
...
},
object_b: {
id: object_b_id
...
}
我知道我可以这样做来获得我想要的东西,但我想知道是否有一种 DRY 方法可以在没有所有包含和除外的情况下做到这一点。
render json: Thing.all, include: [:object_a, :object_b], except: [:object_a_id, :object_b_id]
output => {
id: ....
object_a: {
id: object_a_id
...
},
object_b: {
id: object_b_id
...
}
解决方案
DRY 方法在您的模型中,您可以定义一个 attributes
方法并让其 return 您希望渲染函数使用的对象的形状。
# thing.rb
def attributes
# Return the shape of the object
# You can use symbols if you like instead of string keys
{
'id' => id, # id of the current thing
'other_fields' => other_fields, # add other fields you want in the serialized result
'object_a' => object_a, # explicitly add the associations
'object_b' => object_b
}
end
关联 object_a
和 object_b
应该正常序列化。如果您想 limit/customize 他们的序列化结果,您可以通过在他们各自的 类 中添加 attributes
方法来为他们重复相同的方法。
因此,当在单个或一组事物模型上调用 render json:
时,json 对象的形状 returned 将如定义上面的方法。
注:
需要注意的是,return在 attributes
中编辑的散列中的键名称必须与方法名称(或关联名称)相匹配。我不太清楚为什么。但是我在需要添加名称与其对应列不同的键时使用的解决方法是在我要使用的键名的模型中创建一个方法。
例如,假设您的 Thing
模型有一个列 name
,但是在您的 json 结果中您希望与该列对应的键名称被称为 name_of_thing
.您将执行以下操作:
def name_of_thing
name
end
def attributes
{
'name_of_thing' => name_of_thing,
# other fields follow
# ...
}
end
条件逻辑
条件依赖于模型中的fields/associations
attributes
方法可以支持基于模型中字段的条件。
# thing.rb
def attributes
result = {}
result['id'] = id
# add other fields
# For example, if association to object_a exists
if object_a
result.merge!({
'object_a' => object_a
})
end
# return result
result
end
条件取决于模型外部的输入
如果你想让你的方法在不同的地方呈现不同的字段,你可以做的一件事是覆盖 as_json
方法,它可以更好地处理这些情况,因为此方法接受参数中的选项。
# thing.rb
def as_json(options = {})
result = {}
result['id'] = id
# add other fields to result
if(options[:show_only_ids])
result.merge!({
'object_a_id' => object_a_id,
'object_b_id' => object_b_id
})
else
result.merge!({
'object_a' => object_a,
'object_b' => object_b
})
end
# return result
result
end
然后您需要修改您的控制器(或任何您调用 Thing
模型序列化的地方)以在必要时传递适当的选项。
# thing_controller.rb
render json: Thing.all.as_json({ show_only_ids: true })
渲染时,您不必总是明确指定 as_json
。默认情况下,渲染函数无论如何都会调用它。当你想传递选项时,你只需要明确地进行调用。
我想 return 所有只有关联的事物模型对象没有 asscoiation_id
,有没有更好的方法来做到这一点没有 include
和 except
?
# Thing.rb
belongs_to :object_a
belongs_to :object_b
# create_thing.rb
def change
create_table :things, id: false do |t|
t.string :id, limit: 36, primary_key: true
t.string :object_a_id, foreign_key: true
t.string :object_b_id, foreign_key: true
t.timestamps
end
end
# things_controller.rb
render json: Thing.all, include: [:object_a, :object_b]
output => {
id: ....
object_a_id: 'object_a_id',
object_b_id: 'object_b_id',
object_a: {
id: object_a_id
...
},
object_b: {
id: object_b_id
...
}
我知道我可以这样做来获得我想要的东西,但我想知道是否有一种 DRY 方法可以在没有所有包含和除外的情况下做到这一点。
render json: Thing.all, include: [:object_a, :object_b], except: [:object_a_id, :object_b_id]
output => {
id: ....
object_a: {
id: object_a_id
...
},
object_b: {
id: object_b_id
...
}
解决方案
DRY 方法在您的模型中,您可以定义一个 attributes
方法并让其 return 您希望渲染函数使用的对象的形状。
# thing.rb
def attributes
# Return the shape of the object
# You can use symbols if you like instead of string keys
{
'id' => id, # id of the current thing
'other_fields' => other_fields, # add other fields you want in the serialized result
'object_a' => object_a, # explicitly add the associations
'object_b' => object_b
}
end
关联 object_a
和 object_b
应该正常序列化。如果您想 limit/customize 他们的序列化结果,您可以通过在他们各自的 类 中添加 attributes
方法来为他们重复相同的方法。
因此,当在单个或一组事物模型上调用 render json:
时,json 对象的形状 returned 将如定义上面的方法。
注:
需要注意的是,return在 attributes
中编辑的散列中的键名称必须与方法名称(或关联名称)相匹配。我不太清楚为什么。但是我在需要添加名称与其对应列不同的键时使用的解决方法是在我要使用的键名的模型中创建一个方法。
例如,假设您的 Thing
模型有一个列 name
,但是在您的 json 结果中您希望与该列对应的键名称被称为 name_of_thing
.您将执行以下操作:
def name_of_thing
name
end
def attributes
{
'name_of_thing' => name_of_thing,
# other fields follow
# ...
}
end
条件逻辑
条件依赖于模型中的fields/associations
attributes
方法可以支持基于模型中字段的条件。
# thing.rb
def attributes
result = {}
result['id'] = id
# add other fields
# For example, if association to object_a exists
if object_a
result.merge!({
'object_a' => object_a
})
end
# return result
result
end
条件取决于模型外部的输入
如果你想让你的方法在不同的地方呈现不同的字段,你可以做的一件事是覆盖 as_json
方法,它可以更好地处理这些情况,因为此方法接受参数中的选项。
# thing.rb
def as_json(options = {})
result = {}
result['id'] = id
# add other fields to result
if(options[:show_only_ids])
result.merge!({
'object_a_id' => object_a_id,
'object_b_id' => object_b_id
})
else
result.merge!({
'object_a' => object_a,
'object_b' => object_b
})
end
# return result
result
end
然后您需要修改您的控制器(或任何您调用 Thing
模型序列化的地方)以在必要时传递适当的选项。
# thing_controller.rb
render json: Thing.all.as_json({ show_only_ids: true })
渲染时,您不必总是明确指定 as_json
。默认情况下,渲染函数无论如何都会调用它。当你想传递选项时,你只需要明确地进行调用。