Можно ли автоматически возвращать виртуальные атрибуты в моделях Rails?

Дано:

class Foo
  has_one :bar

  def bar_name
    bar.name
  end
end

class Bar
  belongs_to :foo
end

В консоли или в представлении я могу @foo.bar_name получить 'baz',

Я знаю, что могу @foo.as_json(methods: :bar_name) получить {"id"=>"abc123", "bar_name"=>"baz"},

Я также мог бы денормализовать атрибут и сделать его не виртуальным, но я бы не хотел этого делать в этом случае.

Можно ли автоматически вернуть модель с включенным виртуальным атрибутом?

#<Foo id: "abc123", bar_name: "baz">

Я хочу сделать это, потому что я создаю большой объект с вложенными коллекциями моделей, и as_json звонок отвлечен от меня.

2 ответа

Решение

Не уверен на 100%, что я понимаю, связано ли ваше беспокойство с as_json но если это так, это будет работать

class Foo
  has_one :bar

  def bar_name
    bar.name
  end
  def as_json(options={})
    super(options.merge!(methods: :bar_name))
  end
end

Теперь вызов @foo.as_json будет по умолчанию включать bar_name как ваш явный пример делает.

Гадкий не рекомендовал бы, но вы можете изменить проверку Foo, например #<Foo id: "abc123", bar_name: "baz"> следующее

class Foo
  def inspect
    base_string = "#<#{self.class.name}:#{self.object_id} "
    fields = self.attributes.map {|k,v| "#{k}: #{v.inspect}"}
    fields << "bar_name: #{self.bar_name.inspect}"
    base_string << fields.join(", ") << ">"
  end
end

Тогда "контрольная запись" покажет эту информацию, хотя мне все еще неясно, является ли это вашим намерением, и если да, то почему вы этого хотите.

Вы могли бы использовать attr_accessor - по документации Rails:

Определяет именованный атрибут для этого модуля, где имя - это symbol.id2name, создавая переменную экземпляра (@name) и соответствующий метод доступа для его чтения. Также создает метод с именем name= для установки атрибута.

Другие вопросы по тегам