У меня есть приложение, в котором мои пользователи могут иметь набор настроек. Оба сохраняются как ActiveRecord-модель следующим образом:Rails: создать ассоциацию, если не найдено, чтобы избежать ошибок nil
class User < AR::Base
has_one :preference_set
end
class PreferenceSet < AR::Base
belongs_to :user
end
теперь я могу получить доступ к предпочтениям пользователя:
@u = User.first
@u.preference_set => #<PreferenceSet...>
@u.preference_set.play_sounds => true
Но это не удается, если набор предпочтения не создан, так как @u. preference_set будет возвращать нуль, и я буду звонить play_sounds
по телефону nil
.
Что я хочу архивировать, так это то, что User.preference_set всегда возвращает экземпляр PreferenceSet. Я попытался его определения, как это:
class User < ..
has_one :preference_set
def preference_set
preference_set || build_preference_set
end
end
Это вызывает 'Stack level too deep'
, так как он вызывает себя рекурсивно.
Мой вопрос заключается в следующем:
Как я могу гарантировать, что @user.preference_set
возвращает либо соответствующий preference_set-запись или, если таковой не существует, строит новый?
Я знаю, что могу просто переименовать свою ассоциацию (например, preference_set_real
) и избежать рекурсивных вызовов таким образом, но для простоты в своем приложении я хотел бы сохранить именование.
Спасибо!
Wow, не попадаются alias_method_chain. Это круто. – Chowlett
Следует иметь в виду, что 'alias_method_chain' устарел в пользу' Module # prepend'. Больше информации здесь: https://github.com/rails/rails/pull/19434 –