Виртуальные атрибуты ActiveRecord в качестве атрибутов записи
У меня проблема с to_json, не отображающим мои виртуальные атрибуты
class Location < ActiveRecord::Base
belongs_to :event
before_create :generate_oid
validates_associated :event
attr_accessor :event_oid
def event_oid
@event_oid = event.oid
end
end
event_oid не является частью массива, возвращаемого:
Location.first.attributes
Это особенно проблема для меня при использовании to_json, который автоматически сериализует атрибуты записи для jason. to_json опускает мой виртуальный атрибут.
Как вы можете сделать виртуальный атрибут обработанным как фактический атрибут экземпляра?
Изменить:
to_json - это всего лишь пример метода, где мой виртуальный атрибут, обработанный как фактический атрибут, будет приятным.
Ответы
Ответ 1
Вы хотите изменить хэш атрибутов. Здесь содержится немного дополнительного кода, чтобы гарантировать, что нужные вам атрибуты готовы к использованию с to_json или другим методом, который зависит от атрибутов загрузки объектов.
class Location < ActiveRecord::Base
belongs_to :event
before_create :generate_oid
validates_associated :event
after_save :event_oid
attr_accessor :event_oid
def event_oid
@event_oid = @attributes["event_oid"] = event.oid if event.nil?
end
def after_initialize
event_oid
end
end
to_json и множество других методов, которые генерируют списки вещей на основе атрибутов объектов. Что заполняется при инициализации объекта таблицами и именами базы данных, к сожалению, переменные экземпляра не обновляют этот хеш.
P.S. это не очень DRY, если у вас есть несколько атрибутов, которые вы хотите использовать таким образом. Вы можете использовать массив символов, детерминированных имен методов и блок class_eval для одновременного применения этого процесса к нескольким символам.
Внимание
Мы возимся с внутренностями рельсов. Там не сказано, как это может привести к провалу других вещей. Я не тестировал больше, чем save и to_json, оба из которых работают, когда хэш атрибутов содержит ключи, которые также не являются именами столбцов. Поэтому используйте его на свой страх и риск.
Ответ 2
Как насчет to_json(:methods => [:event_oid])
, это работает?
Ответ 3
Просто выполните #to_json самостоятельно:
class Location < ActiveRecord::Base
def to_json(options={})
options[:methods] ||= []
options[:methods] << :event_oid
super(options)
end
end
Ответ 4
Я попробовал François Beausoleil ответить и получил его для работы после изменения to_json
до as_json
def as_json(options={})
options[:methods] ||= []
options[:methods] << :class_to_s
super(options)
end
Ответ 5
location.to_json(:methods => :event_oid)
Как объясняется здесь: http://apidock.com/rails/ActiveRecord/Serialization/to_json
В контроллере просто используйте:
format.json { render json: @location.to_json(:methods => :event_oid) }
Ответ 6
Старый вопрос, но то, что задал ОП, теперь возможно и просто, если вы знаете, как это сделать.
Вот полный работающий пример, но все, что вам нужно, находится в классе Location.
Оператор attribute
расширяет атрибуты модели, а after_initialize
заботится о присвоении значения.
require 'active_record'
ActiveRecord::Base.establish_connection(
:adapter=> "sqlite3",
:database=> ":memory:"
)
ActiveRecord::Schema.define do
create_table :events do |table|
table.column :name, :string
end
create_table :locations do |table|
table.column :name, :string
table.column :event_id, :integer
end
end
class Event < ActiveRecord::Base
has_one :location
end
class Location < ActiveRecord::Base
belongs_to :event
attribute :event_name, :string
after_initialize do
self.event_name = event.name
end
end
Event.create(name: 'Event1')
Location.create(name: 'Location1', event_id: 1)
p Model.attribute_names
p Event.first
p Event.first.location
#["id", "name", "event_id", "event_name"]
#<Event id: 1, name: "Event1">
#<Location id: 1, name: "Location1", event_id: 1, event_name: "Event1">