Здесь происходит несколько вещей одновременно:
- Блок вызывается в контексте сохраняемого экземпляра модели, поэтому
self
в блоке является сохраняемым User
. Блок также получает аргумент, но вам не нужно его использовать.
- Локальные переменные в Ruby не объявляются явно, они неявно объявляются при первой попытке дать им значение.
- Неявный получатель для вызовов методов:
self
.
- Но локальные переменные имеют приоритет над вызовами методов, поэтому метод-мутатор (например,
self.email=
) нуждается в явном приемнике, чтобы отличать его от локальной переменной.
- Переменные экземпляра (
@email
) не имеют ничего общего с атрибутами в моделях ActiveRecord.
- Метод доступа (
self.email
или просто email
, если нет локальной переменной email
) и методы мутатора (self.email=
) для объектов ActiveRecord работают с атрибутами, а не с переменными экземпляра.
Итак, это:
before_save { self.email = email.downcase } # (1)
также можно записать как:
before_save { |user| user.email = user.email.downcase } # (2)
или даже:
before_save { |user| user.send(:email=, user.send(:email).downcase) } # (3)
Основное функциональное отличие состоит в том, что (2) требует, чтобы методы email
и email=
были общедоступными.