仅在#valid?

时间:2015-10-30 21:15:37

标签: ruby-on-rails ruby-on-rails-4

我有一个带有字段的模型,我在该字段中验证内容。我正在使用ActiveRecord验证来检查该内容的存在。但是,我希望能够保存,更新等,而无需检查有效性。我确实希望在特定时间获得有效性,并从中检索错误。

validates :my_content_in_field, presence: true, if: :should_validate
attr_accessor :should_validate

我想要传递

valid?

这将失败

valid?(should_validate: true)

验证失败后,我希望所有更新和保存按常规工作。这可能吗?我本质上想要利用ActiveRecords错误消息,但实际上并没有验证。

在星期五结束的一天结束时,我可能只是遗漏了一些明显的东西。

4 个答案:

答案 0 :(得分:3)

I'm not sure you can call valid?(should_validate: true). valid? method may be called with one parameter called context (see docs). You should read a great post on validation contexts.

This should work:

class MyModel < ActiveRecord::Base
  validates :something, on: :should_validate
  ...
end

m = MyModel.new
m.valid?                    # No validation happens
m.valid?(:should_validate)  # Validates something

答案 1 :(得分:1)

I think the most efficient way is defining a specific method in your code like this:

class Model < ActiveRecord::Base
  validates :my_content_in_field, presence: true, if: :should_validate
  attr_accessor :should_validate
  alias :super_valid? :valid? 

  # Define a custom loose validation method that
  # will ignore :my_content_in_field
  # 
  # As for the following method, the `context` param
  # is needed to replicate the default signature
  # of `ActiveRecord::Validations::valid?`
  def loosely_valid?(context = nil)
    @should_validate = false
    super_valid? context
  end

  # Tweak the base valid? method
  def valid?(context = nil)
    @should_validate = true
    super_valid? context
  end
end

You will always validate the :my_content_in_field parameter using the standard valid? method unless when you call loosely_valid? that will ignore that parameter forcing the @should_validate attribute in your model.

This is achieved using a simple alias call at the beginning of the method to override the standard valid? method from ActiveRecord.

This approach will always validate :my_content_in_field when creating/updating the model. If you don't need this you can change the code changing those methods like this:

  def strictly_valid?(context = nil)
    @should_validate = true
    super_valid? context
  end

  def valid?(context = nil)
    @should_validate = false
    super_valid? context
  end

答案 2 :(得分:0)

The best I've been able to come up with is creating a custom method:

validates :my_content_in_field, presence: true, if: :should_validate
attr_reader :should_validate

def has_valid_data?
  @should_validate = true

  stored_valid = valid?

  @should_validate = false

  stored_valid
end

So now I get the desired behavior:

valid? #=> true
has_valid_data? #=> false

And I can collect my ActiveRecord error messages and be on my way. But I'd love to see a better way.

答案 3 :(得分:0)

If you're just trying to leverage ActiveRecord error messages and you never need valid? to consider this field, a better approach would be to use the errors API directly:

def valid_data?
  valid = valid?
  errors.add(:my_field, 'invalid content') unless custom_field_is_valid? # your logic here
  valid && errors.empty?
end

This will run the validation on all your other fields, adding their error messages, and then also add an error message for just this field.