Ruby on rails 在rails 6上未触发保存回调之前

Ruby on rails 在rails 6上未触发保存回调之前,ruby-on-rails,Ruby On Rails,运行测试时: require 'rails_helper' RSpec.describe DailyTask, type: :model do context 'crud' do [...] end context 'validations' do let(:task) { create(:task) } it 'duplicated task, fails' do 2.times do DailyTask.create(ta

运行测试时:

require 'rails_helper'

RSpec.describe DailyTask, type: :model do
  context 'crud' do
    [...]
  end

  context 'validations' do
    let(:task) { create(:task) }

    it 'duplicated task, fails' do
      2.times do
        DailyTask.create(task: task, date: Date.today) 
      end
      expect(DailyTask.count).to eq(1)
    end
  end
end
将触发前保存回调,如图所示:

class DailyTask < ApplicationRecord
  belongs_to :task

  validates_presence_of :date

  before_save :is_there_a?

  def is_there_a?
    DailyTask.where(date: self.date, task_id: self.task_id).empty?
  end
end
然而,它似乎没有被触发。已尝试将其更改为“验证前”,但无效。这是一种愚蠢的错误,除非有人指出,否则你是看不到的

编辑:在调用before\u validation的地方粘贴了较旧版本的代码。

调用before\u save回调。尝试在方法中添加调试器,请参见!但它并没有做你想做的事情——你的代码中有一个bug

要修复代码,如果检查失败,则需要添加验证错误。您当前的方法只是检查任务是否存在;它实际上对这些信息没有任何作用

你可以这样写:

validate :is_there_a?

def is_there_a?
  if DailyTask.where(date: self.date, task_id: self.task_id).any?
    errors.add(:date, 'already exists for this task')
  end
end
或者,您可以使用rails',其作用域为:

或者,如果您愿意,也可以将其转换为一行代码:

validates :date, presence: true, uniqueness: { scope: :task_id }
作为一个单独的建议,我个人会写这个测试有点不同。而不是:

it 'duplicated task, fails' do
  2.times do
    DailyTask.create(task: task, date: Date.today) 
  end
  expect(DailyTask.count).to eq(1)
end

您可以考虑编写它以更明确地测试验证:

it 'duplicated task, fails' do
  DailyTask.create(task: task, date: Date.today)
  duplicate_daily_task = DailyTask.new(task: task, date: Date.today)
  expect(duplicate_daily_task).not_to be_valid
end

然后还可以验证重复任务被视为无效的原因。此外,您可能希望考虑使用A来创建记录,而不是直接使用Rails类。

非常感谢!我会采纳你的建议。
it 'duplicated task, fails' do
  DailyTask.create(task: task, date: Date.today)
  duplicate_daily_task = DailyTask.new(task: task, date: Date.today)
  expect(duplicate_daily_task).not_to be_valid
end