考虑以下
:company has_many :issues #ticket tracking example
我想要路由,公司中的任何用户都可以转到/ issues /:id(使用默认id列时这很简单)。
但是,我希望有一个特定于公司的问题ID(因此每个公司都有自己的问题1,2,3等不是唯一的(并且不会使用内部ID)。
在IssueController中针对该公司ID的创建和更新操作中,根据数据库中的最后一个数字计算id是否有更好的方法? (当每个公司更新/创建多个记录时,我可以在这里考虑种族条件的各种问题。)
提前致谢!
答案 0 :(得分:1)
我会将issue_id
处理降低到模型级别。您可以使用before_validation回调来设置issue_id
。仅此一项,即使save
调用包含在事务中,也不会阻止竞争条件。您必须通过@PinnyM建议的[ :company_id, :issue_id ]
表添加索引/唯一约束来进一步确保这对夫妇issues
的唯一性。像这样的东西
class Issue < ActiveRecord::Base
attr_accessible :company_id, :issue_id
belongs_to :company
before_validation :set_issue_id
private
def set_issue_id
self.issue_id = self.company.issues.size + 1
end
end
class Company < ActiveRecord::Base
has_many :issues
end
并在迁移中:
add_index :issues, [:issue_id, :company_id], :unique => true
你可以像你说的那样在控制器中抓住正确的问题:
@issue = Issue.where(company_id: current_user.company.id, issue_id: params[:id])
请注意,在实际发生的情况下,这不提供从约束违例异常中恢复的方法。有关如何处理此问题的建议,请参阅@PinnyM答案。
希望这有帮助。
答案 1 :(得分:1)
第一次误解了这个问题之后,我会再拍一次。
您正在寻找一种方法来解决特定于company_id的问题“计数器”(模拟ID)。虽然@deivid在正确的轨道上,依赖issues.count
只有在你可以保证公司一次不会发出多个请求的情况下才会起作用。这通常是这种情况,但不能保证,不应单独用作此计数器背后的核心逻辑。
您需要为issues
表添加唯一约束/索引 - 这将确保计数器不会重复:
add_index :issues, [:issue_id, :company_id], :unique => true
在模型中添加:uniqueness
约束只会通过使竞争条件的窗口更小来缓解问题,但它不能完全保证唯一性。
请注意,如果数据库中存在约束违规,ActiveRecord无法在事务中从中恢复。您可以尝试抢救ActiveRecord::RecordNotUnique
,重新创建issue
(或者只使用新的issue_id
重新生成count
)并再次保存。