【问题标题】:Rails one-to-many: Validate field valueRails 一对多:验证字段值
【发布时间】:2017-09-14 22:24:31
【问题描述】:

假设我有两个班级

    class student < ApplicationRecord
      has_many :books
    end

    class Book < ApplicationRecord
      belongs_to :student
    end

每本书都有一个布尔变量read,表示该书是否已被阅读。每个学生只能读一本书。如果学生的任何一本书被标记为已读,他的其他书将无法再阅读。

是否有 PSQL 或活动记录验证允许此约束发生?

具体来说,book.update_attributes!(read: true) 将检查其他相关书籍。数据库约束会更受欢迎。

非常感谢!

更新问题陈述:

read 变成一个时间戳 read_at,book.update_attributes!(read_at: Time.zone.now) 将检查学生之前是否阅读过任何其他书籍。

【问题讨论】:

  • 因此,当在 Book 表中创建记录时,read 将设置为 false,并在阅读该书时更新为 true...一旦阅读了任何书籍,将另一本书的 read 值更改为 true 的任何尝试都应该失败,对吗?
  • 书籍在创建时读取默认为 false 并在读取时更新为 true。任何将同一学生的阅读值的不同书籍更改为 true 的尝试都应该失败

标签: ruby-on-rails postgresql validation activerecord psql


【解决方案1】:

在布尔值 read 字段和整数 student_id 字段上添加唯一的部分索引,其中 read 等于 true

add_column :books, :read, :boolean, null: false, default: false
add_index :books, [:student_id, :read], unique: true, where: "read=true"

在 Book 模型中添加唯一验证,该验证仅在 book.read == true 时有效

validates :read, uniqueness: { scope: :student_id }, if: -> (book) { book.read }

【讨论】:

  • 这验证了唯一性。你知道allow_false: true和allow_nil: true有什么关系吗?
  • 是的,你是对的。我已经更新了我的答案并进行了测试。
  • validates :read, uniqueness: { scope: :student_id }, if: 'read.present?' 我认为这也可以。
  • 更新这个问题:如果读取变成时间戳read_at怎么办。一个学生仍然只能读一本书。具体来说, book.update_attributes!(read_at: Time.zone.now) 将检查该学生是否阅读过任何其他书籍。架构应该是什么样的?
  • 尝试将where: "read=true" 更改为where: "read_at IS NOT NULL"。可能需要添加自定义验证来检查唯一性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-04
  • 2012-10-18
  • 2016-11-24
  • 1970-01-01
  • 2020-05-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多