ruby-on-rails - mongoid 中具有 embeds_many 关联的 first_or_create 方法

标签 ruby-on-rails mongodb ruby-on-rails-4 mongoid

我有用于 omni-auth 身份验证的 User 模型。我已对其进行设置,以便可以使用不同的提供商(如 facebook、google 帐户)进行登录。如果在使用这些提供商注册时电子邮件已在数据库中,则用户已登录到该帐户。

类用户 包括 Mongoid::Document embeds_many:供应商 字段:电子邮件,类型:字符串,默认值:“” 结尾 类提供者 包括 Mongoid::Document 字段:名称,类型:字符串 字段:uid,类型:字符串 嵌入_in:用户 结尾

我正在使用 from_omniauth 方法根据身份验证信息查找用户。

def from_omniauth(auth) user=User.find_by(email: auth.info.email) 如果用户返回用户 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] 结尾 结束

但是当它找不到用户并尝试创建一个用户时,我遇到了一个错误。 Mongoid::Errors::UnknownAttribute: 信息: 试图为模型用户设置不允许的“providers.name”值。

但是为什么它认为这是动态字段生成,因为我已经定义了关联。我也尝试了 find_or_initialize 方法,但同样的错误。

谁能帮我弄清楚。提前致谢。

最佳答案

这里有一些魔法。

当您根据上述条件调用#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: ""

对于您的用户模型 - 否则您会像以前一样收到关于动态字段的投诉 - 只是这次是关于不同的字段。

关于ruby-on-rails - mongoid 中具有 embeds_many 关联的 first_or_create 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37075602/

相关文章:

ruby-on-rails - form_for 嵌套资源(单数)未使用正确的路径助手

ruby-on-rails - railstutorial.org - 未定义的方法 `Factory'

mongodb - 构建mongo容器并导入数据

javascript - JavaScript 函数的行为出现问题 `return this`

ruby-on-rails - Rails 中的电话号码验证正则表达式

ruby-on-rails - 拦截ActiveRecord establish_connection初始化过程

ruby-on-rails - 在 Web 应用程序中显示最新的提交值?

java - mongo 无法连接到 [localhost/127.0.0.1 :27017]

javascript - 我可以在 JavaScript 上使用 img 标签来显示存储在 MongoDB 中的图像吗?

ruby-on-rails - Omniauth 错误 -- PG::Error: ERROR: 重复键值违规