gpt4 book ai didi

ruby-on-rails - 克隆新创建的记录时忽略验证

转载 作者:行者123 更新时间:2023-12-02 02:45:10 27 4
gpt4 key购买 nike

我有一个模型UserFile,它belongs_to一个Folder:

class UserFile < ActiveRecord::Base
has_attached_file :attachment
belongs_to :folder

validates_attachment_presence :attachment
validates_presence_of :folder_id

def copy(target_folder)
new_file = self.clone
new_file.folder = target_folder
new_file.save!
end
end

以下测试意外失败:

test 'cannot copy a file to anything other than a folder' do
folder = Factory(:folder)
file1 = UserFile.create(:attachment => File.open("#{Rails.root}/test/fixtures/textfile.txt"), :folder => Folder.root)
file2 = UserFile.find(file1)

# Should pass, but fails
assert_raise(ActiveRecord::RecordInvalid) { file1.copy(nil) }

# Same record, but this DOES pass
assert_raise(ActiveRecord::RecordInvalid) { file2.copy(nil) }

assert file1.copy(folder)
end

使用新创建的对象时,validates_presence_of :folder_id 会被忽略,但是当我执行 ActiveRecord#find 时,它确实有效。我认为这与在copy方法中调用clone有关,但我无法弄清楚。有谁知道发生了什么事或如何使测试通过?

最佳答案

米莎,克隆是一种野兽。

record.errors 被内存,@errors 实例变量也被克隆。

file1.errors = new_file.errors

由于 createfile1 调用了验证,因此该值将非零。

现在,当您克隆 file1 并说 new_file.save! 时会发生什么?在 valid? 深处调用 new_file 上的errors.clear,但它仍然指向与 file1 相同的错误对象。现在恶意的是,存在验证器是这样实现的:

def validate(record)
record.errors.add_on_blank(attributes, options)
end

它(显然)只能访问errors.base http://apidock.com/rails/ActiveModel/Errors/add_on_blank

因此,虽然验证确实在 new_file 作为记录上运行,但存在验证自

new_file.errors.instance_eval { @base } == file1

并且 file1.folder_id 不为空。

现在,您的第二个测试通过了,因为如果您从数据库读取文件条目,file2.errors 为零,因此当您克隆它并在克隆上调用验证时,将重新创建错误对象具有正确的基础(克隆),由于 new_file.folder = target_folder 行,folder_id 将为空。

只需添加即可解决您的问题

def copy(target_folder)
new_file = self.clone
new_file.instance_eval { @errors = nil } # forces new error object on clone
new_file.folder = target_folder
new_file.save!
end

希望这有帮助

关于ruby-on-rails - 克隆新创建的记录时忽略验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6126569/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com