Ruby on Rails / ActiveRecord:使用first_or_initialize更新记录会导致RecordNotUnique

时间:2017-10-30 20:02:04

标签: ruby-on-rails ruby activerecord devise omniauth

我目前从SAML断言中获取用户数据,并根据该信息在本地数据库中创建用户:

mapped_role = map_role user_role
user = User.where(email: auth_attrs.single('Email')).first_or_initialize do |u|
  u.firstname = auth_attrs.single('First Name')
  u.uid = auth_attrs.single('UID')
  u.provider = resp.provider
  u.role = mapped_role
 end

这很有效,但是当用户的详细信息发生变化(例如,他们的角色发生变化)时,该数据不会在数据库中更新。我尝试过做的是将角色分配从do块移出(user上返回的first_or_initialize对象),然后调用后续{{1} },但是这会产生一个漂亮的红色屏幕,通知我该列'电子邮件'并不是唯一的。我不想在这里创建新记录,只是更新现有记录。有没有更好的模式在这里使用?

编辑:我已经尝试了here列出的各种方法,但它们会导致相同的SQLite3错误。好像我在那里遗漏了一些东西。

Edit2:看起来这可能是因为Devise尝试使用自己的电子邮件字段(?)在幕后做某事。

1 个答案:

答案 0 :(得分:2)

我想我会这样做

mapped_role = map_role user_role
# find the user or initatiate an new un-persisted user
user = User.find_or_initialize_by(email: auth_attrs.single('Email'))
attributes = {firstname: auth_attrs.single('First Name'), 
              uid: auth_attrs.single('UID'), 
              provider: resp.provider, 
              role: mapped_role}
# attempt to update the above record with the appropriate attributes 
# this will set the attributes and fire #save
if user.update(attributes)
  # successful
else
  # handle validation errors 
end

这样就不需要对已经持久化的用户和新用户进行逻辑处理。