【问题标题】:rails belongs_to optional but check exists if passedrails belongs_to 可选,但如果通过则检查存在
【发布时间】:2019-08-16 19:01:00
【问题描述】:

我想在 belongs_to 中选择一个属性,因为用户不必立即属于团队。

class User < ActiveRecord::Base
  belongs_to :team, optional: true
end

在未传入team_id 的情况下创建用户:

irb(main):001:0> User.create()
D, [2019-08-16T18:56:53.961520 #1] DEBUG -- :    (0.4ms)  BEGIN
D, [2019-08-16T18:56:53.988354 #1] DEBUG -- :   SQL (0.7ms)  INSERT INTO "users" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id"  [["created_at", "2019-08-16 18:56:53.985875"], ["updated_at", "2019-08-16 18:56:53.985875"]]
D, [2019-08-16T18:56:54.017858 #1] DEBUG -- :    (1.0ms)  COMMIT
=> #<User id: 5, provider: nil, uid: nil, name: nil, email: nil, oauth_token: nil, oauth_expires_at: nil, created_at: "2019-08-16 18:56:53", updated_at: "2019-08-16 18:56:53", team_id: nil, pagerduty_id: nil, slack_user_id: nil, admin: false>

这很好,但是当我为这个用户传入team_id 时,rails 在创建用户记录之前不会检查teams 表中是否存在该记录。这可能会导致team_id 被传递给teams 数据库中不存在的团队。

目前我们数据库中的团队:

D, [2019-08-16T18:57:10.745090 #1] DEBUG -- :   Team Load (0.8ms)  SELECT "teams".* FROM "teams"
=> #<ActiveRecord::Relation [#<Team id: 1, pagerduty_service_key: nil, pagerduty_id: nil, name: "something", slack_channel: nil, slack_usergroup: nil>]>

使用team_id2 创建用户仍然有效:

User.create(team_id: 2)
D, [2019-08-16T18:59:12.776053 #1] DEBUG -- :    (1.7ms)  BEGIN
D, [2019-08-16T18:59:12.783799 #1] DEBUG -- :   SQL (1.3ms)  INSERT INTO "users" ("team_id", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["team_id", 2], ["created_at", "2019-08-16 18:59:12.777772"], ["updated_at", "2019-08-16 18:59:12.777772"]]
D, [2019-08-16T18:59:12.789468 #1] DEBUG -- :    (1.9ms)  COMMIT
=> #<User id: 6, provider: nil, uid: nil, name: nil, email: nil, oauth_token: nil, oauth_expires_at: nil, created_at: "2019-08-16 18:59:12", updated_at: "2019-08-16 18:59:12", team_id: 2, pagerduty_id: nil, slack_user_id: nil, admin: false>

从模型中删除 optional: true 可以验证记录是否存在,但它也使得它不再允许使用 NULL 值。有没有一种 Rails 方法可以检查 teams 表中是否存在 team_id 而无需在数据库级别添加外键?

【问题讨论】:

  • 您使用的是什么 Rails 版本和数据库?使用 Postgres 进行测试,当没有传递 team_id 或相应地传递无效的 team_id 时,我得到 ActiveRecord::NotNullViolationActiveRecord::InvalidForeignKey

标签: ruby-on-rails activerecord ruby-on-rails-5


【解决方案1】:

不幸的是,使用 optional 选项它会关闭您的记录的存在验证,但您可以在模型中添加自定义验证:

class User < ActiveRecord::Base
  belongs_to :team, optional: true

  validates_presence_of :team, if: :team_id_present?

private

  def team_id_present?
    team_id.present?
  end
end

【讨论】:

  • 太棒了,这很完美。如果他们还没有团队,我无法将 team_id 属性传递给用户记录,并且如果 team_id 传递给用户创建。效果很好!
猜你喜欢
  • 2013-05-17
  • 1970-01-01
  • 1970-01-01
  • 2012-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多