我正在向Typeform发出GET
请求。如果请求成功,我将响应保存为数据库order
。我的问题在于这个特定部分:
current_user.find_or_create_by(landing_id: item["landing_id]) do |order|
如果用户提交新的 Typeform,该方法将找不到landing_id
,因此将再次创建所有orders
。但是这些orders
已经存在于数据库中,因此每个order
都多次保存到我的数据库中。
我怎样才能避免这种情况?
items = response.parsed_response["items"]
items.each do |item|
@order = current_user.orders.find_or_create_by(landing_id: item["landing_id"]) do |order|
order.landing_id = item["landing_id"]
order.email = item["hidden"]["email"]
order.price = item["hidden"]["price"]
order.project = item["hidden"]["project"]
order.save!
end
end
find_or_create_by的活动记录文档:
请注意,此方法不是原子的,它首先运行 SELECT,如果没有结果,则尝试插入。如果还有其他线程或进程,则两个调用之间存在争用条件,并且可能最终会得到两个相似的记录。
无论如何,您可以通过向user_id
和landing_id
列的组合添加 uniq 约束来解决此问题:
add_index :orders, [:user_id, :landing_id], unique: true
并相应地更改您的代码:
items = response.parsed_response["items"]
items.each do |item|
begin
Order.transaction(requires_new: true) do
@order = current_user.orders.find_or_create_by(landing_id: item["landing_id"]) do |order|
order.landing_id = item["landing_id"]
order.email = item["hidden"]["email"]
order.price = item["hidden"]["price"]
order.project = item["hidden"]["project"]
order.save!
end
end
rescue ActiveRecord::RecordNotUnique
next
end
end