Как использовать драгоценный камень Devise в приложении Rails, где "Пользователь" разделяется между тремя моделями

Скажем, у меня есть следующее приложение Rails 4:

class Person < ActiveRecord::Base
  has_many :email_addresses, as: :emailable
  has_one :user_account
end

class EmailAddress < ActiveRecord::Base
  belongs_to :emailable, polymorphic: true
  # There is an :address column
end

class UserAccount < ActiveRecord::Base
  belongs_to :person
end

У человека может быть несколько адресов электронной почты. У человека также может быть учетная запись пользователя. (Я переместил это в свою собственную модель, потому что не все люди будут пользователями.) Любой пользовательский адрес электронной почты может использоваться как "имя пользователя" при входе в систему.

Учитывая это, я хотел бы использовать драгоценный камень Devise. Я вижу, вы можете указать модель, к которой применяется аутентификация. User широко используется, но я бы использовал UserAccount. Тем не менее, Devise ожидает, что поле электронной почты (имя пользователя) будет в этой модели.

Когда пользователь регистрирует учетную запись пользователя, на самом деле будет создано три связанные записи (Person, EmailAddress и UserAccount). Я не могу понять, как заставить Devise работать с этой настройкой. Есть идеи? Спасибо за любую помощь.

Ответ 1

Одним из вариантов было бы делегирование метода электронной почты из вашего UserAccount в вашу модель электронной почты и переопределение поисковика def self.find_first_by_auth_conditions(warden_conditions), используемого процедурой входа в систему. Я нашел довольно приятное сообщение в блоге, в котором подробно описывается это, и еще один fooobar.com/questions/377419/... который имеет тот же подход. Существует также раздел в документах о том, как подтвердить создание учетной записи несколькими сообщениями электронной почты.

Поскольку ваша установка немного сложнее, вы также можете использовать EmailAddress в качестве своей основной модели разработки и делегировать методы пароля для UserAccount.
Это может быть полезно, если вам нужно подтвердить каждый адрес электронной почты с подтверждением, а не только на учетную запись пользователя. Эта настройка заставила бы вас переопределить этот поисковик, но вы можете столкнуться с другими проблемами с делегированным паролем, который никогда не использовался ранее.

Ответ 2

Если вы используете ActiveRecord,

Сначала добавьте

attr_accessor :email

to user_account (я думаю, что это самый простой способ справиться с формой разработки)

Далее, вам нужно изменить процедуру входа в систему. Тем не менее, в вашем user_account, переопределите метод разработки, такой

  def self.find_for_database_authentication(warden_conditions)
    conditions = warden_conditions.dup
    if email = conditions.delete(:email)
      where(conditions.to_h).includes(:email_addresses).where(email_addresses: {email: email}).first
    else
      where(conditions.to_h).first
    end
  end

вам также может потребоваться определить следующее, чтобы получить работу над кодом выше

class UserAccount < ActiveRecord::Base
  belongs_to :person
  has_many :email_addresses, through: :person

Это должно сработать, я проверил это, используя активную запись, но если вы используете mongoid, возможно, решение будет другим.

Обратите внимание, что я изменил код из deva Как разрешить пользователям выполнять вход с использованием имени пользователя или адреса электронной почты для получения решение.