我试图建模一个错误跟踪器,每个用户都有连续票号的门票:
用户1:
用户2:
默认情况下,Rails为每条记录提供一个唯一的ID,我需要另一个属性,ticket_number,填充在create
并且取决于用户的票数。
我尝试使用Rails,使用before_create
挂钩执行user.tickets.count + 1
,但这似乎并不安全,因为异步工作人员可以同时创建多个票证例如。
我是否可以利用数据库索引在数据库级别处理这个ticket_number,就像它为id发生一样,并将此ticket_number作为属性检索?
答案 0 :(得分:1)
我认为最安全的方法是
ticket_number
user_id, ticket_number
ticket_number
添加user_id
ticket_number
验证程序,以匹配数据库层ticket_number
并解决模型中的竞争条件。通过此设置,您可以确定
before_create :set_ticket_number
值你需要一个
recalculate_number
将计算正确的票号(将分配给在比赛条件下获胜的第一张记录)
和{{1}}方法来处理由于db唯一性约束(竞争条件的输家)而无法持久化的记录。
答案 1 :(得分:0)
所以,你可能想要签出Rails' belongs_to
上的counter_cache
选项会自动执行该行为:
class Ticket
belongs_to :user, counter_cache: true
end
# you need to add `tickets_count` to your `users` table (or `name_of_counter_count`)
class User
has_many :tickets
end
然后,您可以从#tickets_count
的任何实例访问User
。 Rails确保在创建故障单时增加该数量,并在销毁故障时减少该数量。
但是要小心,它使用ActiveRecord回调,因此如果您因某些原因跳过它们,计数器将会失去同步(您可以使用#reset_counters(:counter_name)
重置它们
还有counter_culture宝石将提供更灵活的解决方案。
至于竞争条件,我不是肯定的,但我认为这是在桌子被锁定时在同一交易中完成的。待验证。
注意:根据您的各种验证和业务逻辑,仅在数据库级别处理此问题可能会变得非常棘手。
IMO:如果这个数量对您的应用程序至关重要,那么在您需要它时可能值得查询(SELECT COUNT(...)
)