【问题标题】:skip certain validation method in Model跳过模型中的某些验证方法
【发布时间】:2012-01-16 14:54:25
【问题描述】:

我正在使用 Rails v2.3

如果我有一个模型

class car < ActiveRecord::Base

  validate :method_1, :method_2, :method_3

  ...
  # custom validation methods
  def method_1
    ...
  end

  def method_2
    ...
  end

  def method_3
    ...
  end
end

如您在上面看到的,我有 3 种自定义验证方法,我将它们用于模型验证。

如果我在这个模型类中有另一个方法来保存模型的新实例,如下所示:

# "flag" here is NOT a DB based attribute
def save_special_car flag
   new_car=Car.new(...)

   new_car.save #how to skip validation method_2 if flag==true
end

我想跳过method_2在这个特殊的新车保存方法中的验证,如何跳过某些验证方法?

【问题讨论】:

  • 您的“特种车”是否有任何可以将其与非特种车区分开来的属性?这样就很简单了。
  • 您查看过conditional validation 文档吗?
  • 嗨,我更新了我的帖子以了解保存特殊汽车的方法。基本上,我有一个“标志”参数传递给该方法,如果“标志”为真,我想跳过方法_2的验证
  • @Dave,我已经讨论过了。但是我想要实现的是方法级别,我想知道是否有可能在方法级别上做到这一点,以及如何做到。

标签: ruby-on-rails ruby-on-rails-3 ruby-on-rails-3.1


【解决方案1】:

将您的模型更新为此

class Car < ActiveRecord::Base

  # depending on how you deal with mass-assignment
  # protection in newer Rails versions,
  # you might want to uncomment this line
  # 
  # attr_accessible :skip_method_2

  attr_accessor :skip_method_2 

  validate :method_1, :method_3
  validate :method_2, unless: :skip_method_2

  private # encapsulation is cool, so we are cool

    # custom validation methods
    def method_1
      # ...
    end

    def method_2
      # ...
    end

    def method_3
      # ...
    end
end

然后在你的控制器中放:

def save_special_car
   new_car=Car.new(skip_method_2: true)
   new_car.save
end

如果您通过控制器中的 params 变量获取 :flag,则可以使用

def save_special_car
   new_car=Car.new(skip_method_2: params[:flag].present?)
   new_car.save
end

【讨论】:

  • attr_writer 应该是 attr_accessor 否则你会得到一个 undefined local variable or method 'skip_method' 错误。或者您可以编写自己的阅读器函数,例如skip_method?
  • 感谢您的回答..我为此搜索了很多。对于可能遇到此问题的任何其他人,我认为如果您这样做,您会收到 MassAssignment 错误。您可以通过这样做来避免错误:new_car= Car.newnew_car.skip_method_2= params[:flag].present?
  • @lnreddy 感谢您指出批量分配错误。我已将答案更新到较新的 Rails 版本。
【解决方案2】:

条件验证的基本用法是:

class Car < ActiveRecord::Base

  validate :method_1
  validate :method_2, :if => :perform_validation?
  validate :method_3, :unless => :skip_validation?

  def perform_validation?
    # check some condition
  end

  def skip_validation?
    # check some condition
  end

  # ... actual validation methods omitted
end

查看文档了解更多详情。

根据您的情况调整它:

class Car < ActiveRecord::Base

  validate :method_1, :method_3
  validate :method_2, :unless => :flag?

  attr_accessor :flag

  def flag?
    @flag
  end    

  # ... actual validation methods omitted
end

car = Car.new(...)
car.flag = true
car.save

【讨论】:

  • 实际上,flag 不是基于数据库的属性...所以...还有其他方式吗?
【解决方案3】:

另一种比应用程序代码更适用于迁移脚本的技术是重新定义验证方法以不做任何事情:

def save_special_car
   new_car=Car.new
   new_car.define_singleton_method(:method_2) {}
   new_car.save
end

#method_2 现在被重新定义为对实例 new_car 不执行任何操作。

【讨论】:

    【解决方案4】:

    在验证中使用块,例如:

    validates_presence_of :your_field, :if =>  lambda{|e| e.your_flag ...your condition}
    

    【讨论】:

      【解决方案5】:

      根据天气标志是真还是假,使用方法save(false)跳过验证。

      【讨论】:

      • save(false) 将跳过整个验证,而不仅仅是一种方法。
      • 也是save(validate: false),不是save(false)
      • 在 Rails v2.3 中是 save(false)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-12-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多