Ruby on rails 在Rails JSON序列化中重命名模型关联属性?
我有一个现有的Rails 3应用程序,我正在向其中添加一个JSON API。我们有一个Ruby on rails 在Rails JSON序列化中重命名模型关联属性?,ruby-on-rails,json,serialization,activerecord,ruby-on-rails-3,Ruby On Rails,Json,Serialization,Activerecord,Ruby On Rails 3,我有一个现有的Rails 3应用程序,我正在向其中添加一个JSON API。我们有一个VendorActiveRecord模型和一个EmployeeActiveRecord模型。员工属于供应商。在API中,我们希望在JSON序列化中包含员工的供应商。例如: # Employee as JSON, including Vendor :employee => { # ... employee attributes ... :vendor => { # ..
Vendor
ActiveRecord模型和一个Employee
ActiveRecord模型。员工
属于供应商
。在API中,我们希望在JSON序列化中包含员工
的供应商
。例如:
# Employee as JSON, including Vendor
:employee => {
# ... employee attributes ...
:vendor => {
# ... vendor attributes ...
}
}
这很容易。但是,我有一个业务需求,即公共API不公开内部模型名称。也就是说,对于外部世界,它需要看起来好像供应商
模型实际上被称为业务
:
# Employee as JSON, including Vendor as Business
:employee => {
# ... employee attributes ...
:business => {
# ... vendor attributes ...
}
}
对于顶级对象,这很容易做到。也就是说,我可以调用@employee.as_json(:root=>:dude\u who\u works\u here)
将employee
重命名为json中的dudewhowworkshere
。但对于包含在内的协会呢?我尝试了几件事,但都没有成功:
# :as in the association doesn't work
@employee.as_json(:include => {:vendor => {:as => :business}})
# :root in the association doesn't work
@employee.as_json(:include => {:vendor => {:root => :business}})
# Overriding Vendor's as_json doesn't work (at least, not in a association)
# ... (in vendor.rb)
def as_json(options)
super(options.merge({:root => :business}))
end
# ... elsewhere
@employee.as_json(:include => :vendor)
我唯一的另一个想法是手动重命名密钥,如下所示:
# In employee.rb
def as_json(options)
json = super(options)
if json.key?(:vendor)
json[:business] = json[:vendor]
json.delete(:vendor)
end
return json
end
但这似乎不雅。我希望有一种更干净、更像Rails-y的方式来做我想做的事情。有什么想法吗?尝试使用as_JSON的内置选项生成复杂的JSON很笨拙。在您的模型中,我会将
重写为_json
,而根本不需要调用super
。为创建自己的选项键作为_json
,以控制要包含在哈希中的内容
# employee.rb
def as_json(options = {})
json = {:name => name, ...} # whatever info you want to expose
json[:business] = vendor.as_json(options) if options[:include_vendor]
json
end
这里有一个偷偷摸摸的方法。创建一个名为Business的模型,映射到供应商表:
class Business < ActiveRecord::Base
set_table_name "vendors"
end
我遇到了同样的问题,因此我将
修改为_json
,以运行递归方法来扫描选项,并将关联的名称切换为别名。无论如何,它适用于我的应用程序,可能也适用于你的应用程序
def self.test_serializer
as_json(
{
:include => {
:contact_info => {as: :contact_info_attributes}
}
}
)
end
def as_json(options={})
data = super(options)
data = as_json_associations_alias_fix(options, data)
return data
end
def as_json_associations_alias_fix options, data, opts = {}
if options[:include].present?
options[:include].each do |include_key, include_hash|
data_key = include_key.to_s
if include_hash[:as].present?
alias_name = include_hash[:as]
data[alias_name.to_s] = data[include_key.to_s]# if !data.is_a?(Array)
data.delete(include_key.to_s)# if !data.is_a?(Array)
data_key = alias_name.to_s
end
# Handle to-one association here, else handle the to-many association.
if !data[data_key].is_a?(Array)
data[data_key] = as_json_associations_alias_fix(include_hash, data[data_key])
else
data[data_key].each_with_index do |value,i|
data[i] = as_json_associations_alias_fix(include_hash, value)
end
end
end
end
return data
end
是的,我以前没想过,这很鬼鬼祟祟。不过,我真的不想为相同的数据使用两个单独的模型。例如,创建新业务并错过任何供应商验证似乎太容易了。
Employee.first.to_json(:only=>:name,:include=>:business)
# "{\"employee\":{\"name\":\"Curly\",\"business\":{\"name\":\"Moe's Garage\"}}}"
def self.test_serializer
as_json(
{
:include => {
:contact_info => {as: :contact_info_attributes}
}
}
)
end
def as_json(options={})
data = super(options)
data = as_json_associations_alias_fix(options, data)
return data
end
def as_json_associations_alias_fix options, data, opts = {}
if options[:include].present?
options[:include].each do |include_key, include_hash|
data_key = include_key.to_s
if include_hash[:as].present?
alias_name = include_hash[:as]
data[alias_name.to_s] = data[include_key.to_s]# if !data.is_a?(Array)
data.delete(include_key.to_s)# if !data.is_a?(Array)
data_key = alias_name.to_s
end
# Handle to-one association here, else handle the to-many association.
if !data[data_key].is_a?(Array)
data[data_key] = as_json_associations_alias_fix(include_hash, data[data_key])
else
data[data_key].each_with_index do |value,i|
data[i] = as_json_associations_alias_fix(include_hash, value)
end
end
end
end
return data
end