Различия между *, self. * И @* при ссылках на ассоциации/атрибуты в Ruby/Rails Модели/контроллеры

Предполагая модель Rails с постоянными/непостоянными атрибутами, какова наилучшая практика их ссылки? Если вы просматриваете общедоступный код, используются разные шаблоны.

Например, если у вас есть связь от одной модели к другой. В чем разница между использованием self.association_name и @association_name?. Какой предпочтительный способ?

То же, что и с ненастоящими атрибутами, определенными с помощью attr_accessor: attr в моделях. Вы можете ссылаться на них с обоими подходами: self.attr и @attr. Какой предпочтительный способ?

Ответ 1

self.x/self.x=y всегда являются вызовами методов.

(self.x - это просто сахар для self.__send__(:x) и self.x = y действительно просто сахар для self.__send__(:x=, y))

@x, с другой стороны, относится только к переменной экземпляра .

Использование @x не будет работать с AR-ассоциациями, поскольку AR определяет только x/x= (которые являются методами) для его магической операции. (AR по существу просто "захватывает" намеренный доступ через эти методы и маршруты через свои собственные внутренние структуры данных, которые не связаны с любыми подобными именованными переменными экземпляра.)

attr_accessor позволяет "получить доступ к обоим путям", потому что и только потому, что он использует переменную экземпляра с одинаковым именем при ее поддержке (она должна где-то хранят значение). Рассмотрим, что attr_accessor :x эквивалентно:

def x; @x; end
def x= (y); @x = y; end

Счастливое кодирование.

Ответ 2

В большинстве случаев вы предпочитаете использовать attr вместо @attr. Это потому, что метод attr часто устанавливает атрибуты, если он не существует.

Например, этот порядок модели:

model Order
  have_many :items

  def total
    @total ||= items.collect(&:price).sum
  end

  def taxes
    @taxes ||= total * 0.10
  end
end

Эта модель работает vell, если бы я использовал @total вместо total в методе taxes, то вычисление завершится неудачно, если я ранее не вызывал метод total этого объекта.

Как указывает @pst, @association_name не работает для объединения, вы должны использовать метод association_name.

Также self.attr следует использовать только для установки атрибута (вызов self.attr=) при чтении значения, которое лучше использовать attr, см. эта статья: когда используется модель self Rails