2

我有一个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.

4

6 回答 6

4

这是因为您使用的是validates_format_of. 这是一个辅助方法,本质上调用validates_each. 该方法验证特定属性。你可以在这里查看它的来源。

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

改为验证:

validate :check_value

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

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

于 2012-07-18T13:52:34.377 回答
4

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?or就不会调用这些验证。如果您希望在任何时候save都不为 value 分配除 word-like-value 之外的其他值,那么除了在初始化时阻止它之外别无他法:

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
于 2012-07-18T13:56:48.813 回答
1

小心。当@value 为nil 时,其他方法会崩溃。

validate :check_value

def check_value
  errors.add(:base,"value is wrong") and return false if !@value || !@value.match(/^\w+$/)
end
于 2012-07-18T14:01:11.083 回答
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
于 2012-07-18T13:51:05.217 回答
0

验证在保存之前运行,所以如果你想在分配时引发错误,你可以这样做

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

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

于 2012-07-18T14:24:18.333 回答
0

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

    # Trigger validation on initialization.
    def initialize(attributes = {})
      super
      valid?
    end
于 2020-01-29T03:47:41.427 回答