如何在Ruby on Rails模型中进行条件验证?

时间:2016-09-08 10:15:43

标签: ruby-on-rails ruby validation

我有study可以participants。我有一个simple_form,用户可以在其中添加参与者。它看起来有点像桌子:

name | company | email OR mobile | timezone
name | company | email OR mobile | timezone
name | company | email OR mobile | timezone

默认情况下,屏幕有三个fieldset行,如果需要,用户可以添加更多行。每行都是一个参与者。

我希望我的participant模型仅验证已填写的行,并忽略空白行,因为即使我们默认向用户显示三个,但并非所有三个都是必填字段。

这是app/models/participants.rb的相关部分。

class Participant < ApplicationRecord
  belongs_to :study

  validates :name, presence: true
  validates :company, presence: true
  validates :time_zone, presence: true

  if :channel == 'sms'
    validates :mobile_number, presence: true
  elsif :channel == 'email'
    validates :email, presence: true
  end
end

participants_controller.rb我有:

def index
  3.times { @study.participants.build } if @study.participants.length.zero?
end

问题是我收到错误,因为simple_form认为所有三个字段都是必需的,而不仅仅是第一行。

2 个答案:

答案 0 :(得分:2)

滑轨&#39;验证者接受条件:

validates :mobile_number, presence: true, if: Proc.new { |p| p.study.channel == 'sms' }
validates :email,         presence: true, if: Proc.new { |p| p.study.channel == 'email' }

答案 1 :(得分:1)

  

默认情况下,所有输入都是必需的。当表单对象包含时   ActiveModel :: Validations(例如,与Active一起发生)   记录模型),只有存在时才需要字段   验证。否则,Simple Form会将字段标记为可选。对于   性能原因,在验证时跳过此检测   使用条件选项,例如:if和:unless。

     

当然,任何输入的必需属性都可以被覆盖   根据需要:

<%= simple_form_for @user do |f| %>
  <%= f.input :name, required: false %>
  <%= f.input :username %>
  <%= f.input :password %>
  <%= f.button :submit %>
<% end %>

尝试将所有输入设置为 required:false 。这应该允许跳过simple_form验证并且数据进入控制器并且模型可以被过滤或/和验证,并且在持久之前你想要做的其他事情。

在模型类中,您可以使用多种验证方法,例如:

您还可以使用:if和:unless options ,其中的符号对应于将在验证发生之前调用的方法名称。这是最常用的选项。

例如

class Participant < ApplicationRecord
   belongs_to :study

   validates :name, presence: true
   validates :company, presence: true
   validates :time_zone, presence: true
   validates :mobile_number, presence: true if: :channel_is_sms? 
   validates :email, presence: true if: :channel_is_email? 

  def channel_is_sms?
    channel == "sms"
  end

  def channel_is_email?
    channel == "email"
  end
end

或者您也可以使用自定义验证程序来执行您需要验证的所有内容。例如

class MyValidator < ActiveModel::Validator
  def validate(record)
    unless record.channel == 'sms'
      ...
      ...  actions here
      ...
    end
  end
end

class Person
  include ActiveModel::Validations
  validates_with MyValidator
end