SQL如何只得到1个真值

问题描述 投票:0回答:1

我正在建立一个应用程序,我需要能够唱主角老师,我需要防止2个老师共享一个特定班级的主角头衔。

class CreateClassroomTeachers < ActiveRecord::Migration[5.2]
  def change
    create_table :classroom_teachers do |t|
      t.belongs_to :classroom
      t.belongs_to :teacher
      t.boolean    :lead, default: false
    end
    add_index :household_people, [:classroom_id, :teacher_id], unique: true
    # Only one teacher in a classroom can be lead 
  end
end

我的模型里有这个

class ClassroomTeacher < ApplicationRecord
  belongs_to :classroom
  belongs_to :teacher


  validate :only_one_is_lead_teacher

  def only_one_is_lead_teacher
    if lead
      if ClassroomTeacher.where(classroom_id: classroom_id, lead: true).count > 0
        errors.add(:lead, "There can only be one (1) lead teacher per classroom")
      end
    end
  end
end

这方面的问题是,在Create上,我可以让2个或更多的老师来带队。

谢谢你的帮助

ruby-on-rails pg
1个回答
2
投票

有几种方法可以通过约束、触发器等实现。- 取决于你各自的数据库服务器支持什么。

什么 至少在Postgres中是这样的(尽管它可能略微有点黑),就是在 %i[classroom_id lead] 并确保 lead 要么是 trueNULL. 这应该可以,因为Postgres将 NULL 值为不同,这意味着如果多个 NULL 值存储在一个列中,这个列有一个唯一性约束。


如果你想在代码中解决这个问题(我个人不建议这样做,因为你的数据库可能会被你的代码以外的东西访问,甚至你的代码也可以绕过它,比如直接写到数据库而不是使用ActiveRecord的高级方法),这里是我过去的做法。

class ClassroomTeacher < ActiveRecord::Base
  before_save :ensure_only_one_lead_teacher

  private

  def ensure_only_one_lead_teacher
    # We don't have to do this unless the record is the one who should be the (new) lead.
    return unless lead?

    # Set all other records for the class room to lead = false.
    self.class.where(classroom_id: classroom_id).update_all(lead: false)

    # Now if the record gets persisted, it will be the only one with lead = true.
  end
end

一个可能更 "正确 "的方法是在记录被持久化后确保其唯一性。

class ClassroomTeacher < ActiveRecord::Base
  after_commit :ensure_only_one_lead_teacher

  private

  def ensure_only_one_lead_teacher
    # We don't have to do this unless the record is the one who should be the (new) lead.
    return unless lead?

    # Set all other records for the class room to lead = false. Note that we now have to exclude
    # the record itself by id because it has already been saved.
    self.class.where.not(id: id).where(classroom_id: classroom_id).update_all(lead: false)
  end
end

0
投票

根据迁移,模型的属性是ClassroomTeacher: classroom_id, teacher_id, lead。

考虑到老师正在加班。

控制器文件

def create
  ClassroomTeacher.create(teacher_id: data1, classroom_id: data2, lead: data3)
end

可能的样本数据与理想值为。

id classroom_id teacher_id lead
1     1             3       false
2     2             4       true
3     1             2       false
4     1             5       true

现在,你需要避免任何新的教师 被添加到教室作为主角。模型验证代码可以是

validate :only_one_is_lead_teacher

def only_one_is_lead_teacher
  if self.lead
    class_obj = ClassroomTeacher.where(classroom_id: self.classroom_id, lead: true).first
    if class_obj.present?
      self.errors.add(:lead, "There can only be one (1) lead teacher per classroom")
      return false
    end
  end
end
© www.soinside.com 2019 - 2024. All rights reserved.