在mongoid中使用embeds_many关联的first_or_create方法

时间:2016-05-06 14:59:32

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

我有private class MyListAdapter extends ArrayAdapter<String> { public MyListAdapter() { super(getActivity().getApplicationContext(), R.layout.fragment_users_cell, myItemList); } @Override public View getView(final int position, View convertView, ViewGroup parent) { View cellView = convertView; if (cellView == null){ cellView = getActivity().getLayoutInflater().inflate(R.layout.fragment_users_cell, parent, false); } cellProfileImage = (ImageView) cellView.findViewById(R.id.fragment_users_cell_profileImg); System.out.println("The current position" + position); if (resultsImageFiles.get(position)==null) { Bitmap image = BitmapFactory.decodeResource(getActivity().getResources(), R.drawable.ph2); cellProfileImage.setImageBitmap(image); } else { ParseFile file = resultsImageFiles.get(position); file.getDataInBackground(new GetDataCallback() { @Override public void done(byte[] data, ParseException e) { if (e == null) { Bitmap image = BitmapFactory.decodeByteArray(data, 0, data.length); cellProfileImage.setImageBitmap(image); } } }); } return cellView; } } 模型用于omni-auth身份验证。我已将其设置为可以使用不同的提供商(如Facebook,Google帐户)进行登录。如果使用这些提供商注册时电子邮件已在数据库中,则用户将登录该帐户。

User 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

但是当我找不到用户并试图创建一个用户时,我收到了一个错误。 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

但为什么它会将此视为动态字段生成,因为我已经定义了关联。我也尝试了Mongoid::Errors::UnknownAttribute: message: Attempted to set a value for 'providers.name' which is not allowed on the model User. 方法但是同样的错误。

有人可以帮我搞清楚吗?提前谢谢。

1 个答案:

答案 0 :(得分: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: ""

对于您的用户模型 - 否则您将获得与以前相同的有关动态字段的投诉 - 这次是关于不同的字段。