validates_uniqueness_of 在 Heroku 上失败?
在我的用户模型中,我有:
validates_uniqueness_of :fb_uid (我正在使用 facebook connect)。
但是,有时,我会在用户注册时收到重复的行。这非常糟糕。
两条记录的创建时间都在100ms以内。我无法确定它是否发生在两个单独的请求中(heroku 日志记录很糟糕,只能追溯到到目前为止,而且只发生了两次)。
有两件事:
- 有时请求需要一些时间,因为我查询 FB API 的姓名信息、好友和图片。
- 我使用 bigint 来存储 fb_uid (后端是 postgres)。
我无法在开发中复制。
任何想法将不胜感激。
登录功能
def self.create_from_cookie(fb_cookie, remote_ip = nil)
return nil unless fb_cookie
return nil unless fb_hash = authenticate_cookie(fb_cookie)
uid = fb_hash["uid"].join.to_i
#Make user and set data
fb_user = FacebookUser.new
fb_user.fb_uid = uid
fb_user.fb_authorized = true
fb_user.email_confirmed = true
fb_user.creation_ip = remote_ip
fb_name_data, fb_friends_data, fb_photo_data, fb_photo_ext = fb_user.query_data(fb_hash)
return nil unless fb_name_data
fb_user.set_name(fb_name_data)
fb_user.set_photo(fb_photo_data, fb_photo_ext)
#Save user and friends to the db
return nil unless fb_user.save
fb_user.set_friends(fb_friends_data)
return fb_user
end
In my User model, I have:
validates_uniqueness_of :fb_uid (I'm using facebook connect).
However, at times, I'm getting duplicate rows upon user sign up. This is Very Bad.
The creation time of the two records is within 100ms. I haven't been able to determine if it happens in two separate requests or not (heroku logging sucks and only goes back so far and it's only happened twice).
Two things:
- Sometimes the request takes some time, because I query FB API for name info, friends, and picture.
- I'm using bigint to store fb_uid (backend is postgres).
I haven't been able to replicate in dev.
Any ideas would be extremely appreciated.
The signin function
def self.create_from_cookie(fb_cookie, remote_ip = nil)
return nil unless fb_cookie
return nil unless fb_hash = authenticate_cookie(fb_cookie)
uid = fb_hash["uid"].join.to_i
#Make user and set data
fb_user = FacebookUser.new
fb_user.fb_uid = uid
fb_user.fb_authorized = true
fb_user.email_confirmed = true
fb_user.creation_ip = remote_ip
fb_name_data, fb_friends_data, fb_photo_data, fb_photo_ext = fb_user.query_data(fb_hash)
return nil unless fb_name_data
fb_user.set_name(fb_name_data)
fb_user.set_photo(fb_photo_data, fb_photo_ext)
#Save user and friends to the db
return nil unless fb_user.save
fb_user.set_friends(fb_friends_data)
return fb_user
end
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我对 facebook connect 不太熟悉,但是如果来自两个单独帐户的两个单独用户在任一请求完成之前快速连续发布请求,是否有可能获得两个相同的 uuid? (也称为竞争条件)validates_uniqueness_of 仍然会受到这种竞争条件的影响,详细信息可以在此处找到:
http://apidock.com/rails/ActiveModel/Validations/ClassMethods/validates_uniqueness_of
通过添加数据库约束,您确实可以确保这种情况永远不会发生。将其添加到数据库迁移中,然后运行它:
现在用户会收到错误,而无法完成请求,这通常比在数据库中生成非法数据更可取,您必须手动调试和清除这些数据。
I'm not terribly familiar with facebook connect, but is it possible to get two of the same uuid if two separate users from two separate accounts post a request in very quick succession before either request has completed? (Otherwise known as a race condition) validates_uniqueness_of can still suffer from this sort of race condition, details can be found here:
http://apidock.com/rails/ActiveModel/Validations/ClassMethods/validates_uniqueness_of
You can really make sure this will never happen by adding a database constraint. Add this to a database migration and then run it:
Now a user would get an error instead of being able to complete the request, which is usually preferable to generating illegal data in your database which you have to debug and clean out manually.
来自 Ruby on Rails v3.0.5 模块 ActiveRecord::Validations::ClassMethods
http://s831.us/dK6mFQ
From Ruby on Rails v3.0.5 Module ActiveRecord::Validations::ClassMethods
http://s831.us/dK6mFQ
您的代码中似乎存在某种竞争条件。为了检查这一点,我首先更改代码,以便首先提取 facebook 值,然后我才会创建一个新的 facebook 对象。
那么我强烈建议您编写一个测试来检查您的函数是否执行一次。好像执行了两次。
在此基础上,等待获取 facebook 结果时似乎存在竞争条件。
It seems like there is some sort of a race condition inside your code. To check this, i would first change the code so that facebook values are first extracted and only then i would create a new facebook object.
Then i would highly suggest that you write a test to check whether your function gets executed once. It seems that it's executed two times.
And upon this, there seems to be a race condition upon waiting to get the facebook results.