9

私はJSON APIを追加する既存のRails 3アプリケーションを持っています。我々はVendor ActiveRecordモデルとEmployee ActiveRecordモデルを持っています。 EmployeeVendorに属します。 APIでは、EmployeeVendorをJSONシリアライゼーションに含めたいと考えています。例:Rails JSONのシリアル化でモデルアソシエーション属性の名前を変更しますか?

# Employee as JSON, including Vendor 
:employee => { 
    # ... employee attributes ... 
    :vendor => { 
     # ... vendor attributes ... 
    } 
} 

これで十分です。しかし、公開APIが内部モデル名を公開しないというビジネス要件があります。つまり、Vendorモデルが実際にBusinessと呼ばれているように見える必要があり、外の世界に、次のとおりです。

# Employee as JSON, including Vendor as Business 
:employee => { 
    # ... employee attributes ... 
    :business => { 
     # ... vendor attributes ... 
    } 
} 

これは、トップレベルのオブジェクトに対して行うのは簡単です。つまり、@employee.as_json(:root => :dude_who_works_here)に電話して、JSONのEmployeeからDudeWhoWorksHereに名前を変更できます。しかし、付属の団体はどうですか?私は成功せず、いくつかのことを試してみました:私が持っている

# :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方法が私が望むことをすることを望んでいます。何か案は?

答えて

11

as_jsonの組み込みオプションを使用して複雑なJSONを生成しようとすると、不器用です。お使いのモデルではas_jsonを上書きし、superと呼んでも構いません。 as_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 
+0

これは私が恐れていたことです... – thefugal

0

これはやっかいなやり方です。ビジネスと呼ばれるモデルを作成し、ベンダーのテーブルにマップされた:

class Business < ActiveRecord::Base 
    set_table_name "vendors" 
end 

今従業員にbelongs_toの追加:

:オプションとして、「仮想」関連で

class Employee < ActiveRecord::Base 
    belongs_to :vendor 
    belongs_to :business, :foreign_key => :vendor_id 
    ... 
end 

コールto_jsonEmployeeの通過を

Employee.first.to_json(:only=>:name,:include=>:business) 
# "{\"employee\":{\"name\":\"Curly\",\"business\":{\"name\":\"Moe's Garage\"}}}" 
+0

ええ、私は前にそれを考えなかった、それはかなり卑劣です。私は本当に同じデータの2つの別々のモデルを持っているとは思っていません。新しいビジネスを創造し、私が持っているどのようなベンダーの検証にも欠けているような気がします。 – thefugal

0

私は同じ問題に遭遇したので、as_jsonも再帰的な方法を実行してオプションをスキャンし、 eエイリアス名の関連付けの名前。とにかく、それは私のアプリのために働く、あなたのために働くかもしれない。

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 
関連する問題