rails 4 before_validation on :: create或on :: save

and*_*lho 32 validation ruby-on-rails ruby-on-rails-4

我有一个案件正在绕过我的脑袋.

我有一个Image模型,如果上传的话我只想保存.我还需要一些来自上传的信息来验证图像(如高度和宽度).但是我想只有在第一次尝试将文件保存到文件时才会发生上传.

所以我认为最好的选择是拥有一个before_validation,但我希望它只能在保存时运行!

我的代码在这个要点上https://gist.github.com/andreorvalho/b21204977d2b70fdef83

所以奇怪的部分是这个,on: :save并且on: :create有非常奇怪的行为,或者至少不是我的预期.

当我把它作为on: :save我试图做image.save一个测试我可以看到我的before_validation回调没有运行!

如果我on: :create在每种情况下运行都没关系,如果我跑了image.save,image.create或者image.valid?

所以我猜这不是工作,或者我误解了设置的目标.

ps我的创建验证,也发生在每种情况下保存,创建或有效?

让我知道是否有人碰到相同或知道为什么不应该像这样工作.

Jon*_*Jon 65

UPDATE

自从最初编写此答案以来,before_validation回调已更新为允许限制对象生命周期内的特定事件.您现在可以使用以下语法:

before_validation :set_uuid, on: :create
before_validation :upload_to_system, on: [:create, :update]
Run Code Online (Sandbox Code Playgroud)

老答案

before_validation回调将验证之前被执行.每次.你不能限制它before_validationbefore_validation我特别害怕的行动.

你应该做这样的事情:

before_validation :set_uuid, on: :create
before_validation :upload_to_system, on: [:create, :update]
Run Code Online (Sandbox Code Playgroud)

before_validation您传递的选项将在您的验证中使用,就像您在before_validation验证时所做的那样.


rad*_*haw 6

我遇到了同样的问题,这就是我发现的。

#valid?是一种方法,它还接受一个名为的可选参数context(由于某种原因很多人都不知道,包括我在偶然发现这个问题并做了一些研究之前)。调用context#valid?方法时传入 将会导致仅before_validation运行那些context使用该键设置了相同设置的回调:on

例子

假设我们有以下代码:

class Model < ActiveRecord::Base
  before_validation :some_method, on: :create
  before_validation :another_method, on: :update
  before_validation :yet_another_method, on: :save
  before_validation :also_another_method, on: :custom
end
Run Code Online (Sandbox Code Playgroud)

现在,打电话:

Model.new.valid?(:create)
Run Code Online (Sandbox Code Playgroud)

只会运行:some_method。同样调用:

Model.new.valid?(:update)
Model.new.valid?(:save)
Model.new.valid?(:custom)
Run Code Online (Sandbox Code Playgroud)

只会分别运行:another_method:yet_another_method、 和:also_another_method。但是,如果我们这样做:

Model.new.valid?(:unknown)
Run Code Online (Sandbox Code Playgroud)

那么它不会调用任何回调,因为我们:unknown在创建回调时没有指定为上下文。

context另外,另一件事需要注意的是,如果我们在调用时不传递 a #valid?,那么 ActiveRecord 将在内部使用该new_record?方法来计算它。也就是说,如果new_record?返回true,则context会被设置为:create,但如果返回false,则context会被设置为:update

回到你的问题

当我将其设置为“on: :save如果我尝试进行image.save测试”时,我可以看到我的before_validation回调没有运行!

这是因为 ActiveRecord 的#save方法在内部调用时#valid?不传递显式context,这意味着现在该#valid?方法必须根据 . 返回的布尔值来决定是否使用:createor:update作为 a 。由于您已指定,因此它不会运行。是的,没错,ActiveRecord 内部不存在上下文。context#new_record?on: :save:save

如果我on: :create在每种情况下都跑了,那么我跑了并不重要image.saveimage.create或者image.valid?

这是事实,但前提是这image是一个新记录。尝试对现有记录执行相同的操作,它不会运行。