我正在建立一个应用程序,我需要能够唱主角老师,我需要防止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个或更多的老师来带队。
谢谢你的帮助
有几种方法可以通过约束、触发器等实现。- 取决于你各自的数据库服务器支持什么。
什么 应 至少在Postgres中是这样的(尽管它可能略微有点黑),就是在 %i[classroom_id lead]
并确保 lead
要么是 true
或 NULL
. 这应该可以,因为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
根据迁移,模型的属性是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