Переименование атрибутов ассоциации модели в сериализации Rails JSON? - PullRequest
10 голосов
/ 16 декабря 2010

У меня есть приложение Rails 3, к которому я добавляю JSON API.У нас есть модель Vendor ActiveRecord и модель Employee ActiveRecord.Employee принадлежит Vendor.В API мы хотим включить Employee Vendor в сериализацию 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), чтобы переименовать Employee в DudeWhoWorksHere в JSON.Но как насчет включенных ассоциаций?Я попробовал несколько вещей без успеха:

# :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-й способ сделать то, что я хочу.Есть идеи?

Ответы [ 3 ]

11 голосов
/ 16 декабря 2010

Попытка генерировать сложный JSON со встроенными опциями для as_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 голосов
/ 19 апреля 2017

Я столкнулся с той же проблемой, поэтому я изменил as_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
0 голосов
/ 16 декабря 2010

Вот хитрый способ сделать это. Создайте модель с именем Business, сопоставленную с таблицей поставщиков:

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

Теперь добавьте принадлежащего к Сотруднику:

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

Позвоните to_json на Employee, передавая "виртуальную" ассоциацию в качестве опции:

 Employee.first.to_json(:only=>:name,:include=>:business)
 # "{\"employee\":{\"name\":\"Curly\",\"business\":{\"name\":\"Moe's Garage\"}}}" 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...