如何为初始化变量创建验证?

时间:2012-07-18 13:46:02

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

我有一个变量value,它在我创建一个新对象时被初始化。但是,此变量不是我的表的列。我只是想在我的模型中使用它并让它可用于我的类中的一些方法:

class MyClass < ActiveRecord::Base
  def initialize (value)
    @value = value
  end
end

因此,当创建新对象@value时会暂时保留some text,例如:

test = MyClass.new("some text")

有一种方法可以验证变量value是否仅接受文本?

class MyClass < ActiveRecord::Base
  validates_format_of :value => /^\w+$/ # it doesn't work

  def initialize (value)
    @value = value
  end
end

修改

我已经尝试了所有答案,但我的Rspec仍在传递:

我的新课程:

class MyClass < ActiveRecord::Base
  validate :check_value

  def check_value
    errors.add(:base,"value is wrong") and return false if !@value || !@value.match(/^\w+$/)
  end  

  def initialize (value)
    @value = value
  end

  def mymethod
    @value
  end
end

我的Rspec(我原以为它会失败,但它仍在传递):

describe MyClass do
  it 'checking the value' do
    @test = MyClass.new('1111').mymethod
    @test.should == '1111'
  end
end

我想在将1111分配给@value之前提出验证错误。

6 个答案:

答案 0 :(得分:3)

这是因为你正在使用validates_format_of。它是一种辅助方法,基本上调用validates_each。该方法验证特定属性。您可以查看其来源here

由于您尝试验证实例变量而不是属性,因此您必须编写自定义验证器。

使用此验证:

validate :check_value

def check_value
   unless @value && @value.match(/^\w+$/)
      errors.add(:base,"value is wrong") and return false
   end
end

我希望这只是代码的代表性示例。请告诉我你不要使用@value作为变量名。

答案 1 :(得分:2)

只有在模型上调用valid?save时,Rails才会进行验证。因此,如果您希望在调用这些方法时仅接受值的值,请执行自定义验证:

class MyClass < ActiveRecord::Base

  validate :value_string

  #further code

在受保护的范围

下设置您的值验证
protected

  def value_string
    self.errors[:base] << 'Please assign a string to value' unless @value.match(/^\w+$/)
  end

如前所述,如果不调用valid?save,就不会调用这些验证。 如果您希望值不能在任何时候分配另一个值而不是类似值 ,那么除了在初始化时阻止它之外别无他法:

def initialize(attributes = nil, options = {})
  attr_value = attributes.delete(:value) if attributes
  @value = attr_value if attr_value && attr_value.match(/^\w+$/)

  super
end

修改

在初始化时分配不接受的值时,我不建议引发ActiveRecord验证错误。尝试根据ArgumentError

提出自己的自定义错误

课外

YourError = Class.new(ArgumentError)

在课堂内

def initialize(attributes = nil, options = {})
  attr_value = attributes.delete(:value) if attributes
  if attr_value && attr_value.match(/^\w+$/)
    @value = attr_value
  elsif attr_value
    raise YourError.new('Value only accepts words')
  end

  super
end

然后像这样测试

describe Myclass do
  it 'should raise an error if value is assigned with something else than a word' do
    lambda{ MyClass.new(:value => 1111)}.should raise_error(YourError)
  end
  it 'should assign the value for words' do
    MyClass.new(:value => 'word').value.should == 'word'
  end
end

答案 2 :(得分:1)

小心。当@value为零时,其他方法会爆炸。

validate :check_value

def check_value
  errors.add(:base,"value is wrong") and return false if !@value || !@value.match(/^\w+$/)
end

答案 3 :(得分:0)

您应该可以通过创建自己的验证器来完成此操作,如下所示:

class MyClass < ActiveRecord::Base

  validate :value_is_string

  protected

    def value_is_string
      unless @value.match(/^\w+$/)
        self.errors[:base] << 'Please put a string in value'
      end
    end
end

答案 4 :(得分:0)

验证在保存之前运行,因此如果您想在分配时引发错误,可以执行此操作

  def initialize (value)
    raise ActiveRecord::RecordInvalid if !@value || !@value.match(/^\w+$/)
    @value = value
  end

但我不认为这是一个很好的方法

答案 5 :(得分:0)

初始化时只需要调用super。试试这个:

    # Trigger validation on initialization.
    def initialize(attributes = {})
      super
      valid?
    end