2016-05-06 2 views
2

У меня есть модель User, которая используется для аутентификации с использованием аутентификации. Я настроил его так, чтобы для входа в систему могли использоваться разные провайдеры (например, facebook, учетные записи google). Если письмо уже находится в базе данных при регистрации с использованием этих поставщиков, пользователь подписывается на эту учетную запись.метод first_or_create с ассоциацией embeds_many в mongoid

class User include Mongoid::Document embeds_many :providers field :email,type: String, default: "" end class Provider include Mongoid::Document field :name, type: String field :uid, type: String embedded_in :user end

И я использую from_omniauth метод, чтобы найти пользователя на основе информации AUTH.

def from_omniauth(auth) user=User.find_by(email: auth.info.email) return user if user where(:"providers.name" => auth.provider, :"provider.uid" => auth.uid).first_or_create do |user| user.email = auth.info.email user.password = Devise.friendly_token[0,20] end end

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

Но почему он рассматривает это как генерацию динамического поля, поскольку я уже определил ассоциации. Я пробовал find_or_initialize способ тоже но такой же ошибка.

Может кто-нибудь помочь мне понять это. Заранее спасибо.

ответ

0

Здесь есть какая-то магия.

Когда вы вызываете #first_or_create по указанным выше критериям:

where(:"providers.name" => auth.provider, :"provider.uid" => auth.uid).first_or_create do |user| 
    user.email = auth.info.email 
    user.password = Devise.friendly_token[0,20] 
end 

Это на самом деле получить де-сахаре в нечто большее, как это:

found_user_with_provider = where(:"providers.name" => auth.provider, :"provider.uid" => auth.uid).first 
if found_user_with_provider.nil? 
    new_user = User.new 
    new_user.set(:"providers.name", auth.provider) 
    new_user.set(:"providers.uid", auth.uid) 
    new_user.email = auth.info.email 
    new_user.password = Devise.friendly_token[0,20] 
else 
    found_user_with_provider.email = auth.info.email 
    found_user_with_provider.password = Devise.friendly_token[0,20] 
end 

Обратите внимание на попытку установить значение «provider.name» и «provider.uid» как атрибуты в пользовательском экземпляре - что на самом деле не то, что вы хотите, и то, о чем жалуется Mongoid.

Вы на самом деле, вероятно, хотите что-то больше, как это:

def from_omniauth(auth) 
    user = User.find_by(email: auth.info.email) 
    return user if user 
    found_user_with_provider = where(:"providers.name" => auth.provider, :"provider.uid" => auth.uid).first 
    if found_user_with_provider 
    found_user_with_provider.update_attributes!(
     :email => auth.info.email, 
     :password => Devise.friendly_token[0,20] 
    ) 
    return found_user_with_provider 
    end 
    User.create!({ 
    :providers => [ 
     Provider.new({ 
      :name => auth.provider, 
      :uid => auth.uid 
     }) 
    ], 
    :email => auth.info.email, 
    :password => Devise.friendly_token[0,20] 
    }) 
end 

Конечно, есть еще одна проблема, и это, что вы устанавливаете атрибут #password на вашем экземпляре пользователя. Убедитесь в том, чтобы добавить:

field :password,type: String, default: "" 

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

Смежные вопросы