0

考虑以下

:company has_many :issues  #ticket tracking example

我希望有路由,以便公司中的任何用户都可以转到 /issues/:id (使用默认 id 列时这很简单)。

但是,我希望有一个特定于公司的问题 ID(因此每个公司都有自己的问题 1、2、3 等,这些问题不是唯一的(并且不会使用内部 ID)。

有没有比在 IssueController 中为该公司 ID 创建和更新操作中基于数据库中的最后一个数字计算 ID 更好的方法?(当每个公司更新/创建多个记录时,我可以在这里想到各种竞争条件问题)。

提前致谢!

4

2 回答 2

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 答案。

希望这可以帮助。

于 2013-02-18T17:50:21.103 回答
1

在第一次误解了这个问题之后,我会再试一次。

You are looking for a way to have an issue 'counter' (to simulate an id) that is specific to a company_id. Although @deivid was on the right track, relying on issues.count will only work if you can guarantee that a company never makes more than one request at a time. This will generally be the case, but is not guaranteed and shouldn't be used alone as the core logic behind this counter.

You'll need to add a unique constraint/index to your issues table - this will ensure that counter can't be duplicated:

add_index :issues, [:issue_id, :company_id], :unique => true

Adding a :uniqueness constraint in the model will only mitigate the problem somewhat by making the window for the race condition smaller, but it can't guarantee uniqueness completely.

Note that in the event of a constraint violation in the DB, ActiveRecord can't recover from it within the transaction. You can try rescuing ActiveRecord::RecordNotUnique, recreating the issue (or just regenerating the issue_id using a fresh count) and saving again.

于 2013-02-18T18:31:41.293 回答