手动定义getter / setter(attr_accessor或attr_writers)时如何使用read_attribute

时间:2012-08-25 23:20:21

标签: ruby-on-rails validation ruby-on-rails-3.2 models

我设置了search模型,并希望至少填写一个字段。我发现了一个有助于验证的问题Rails: how to require at least one field not to be blank。 (我尝试了所有答案,但Voyta似乎是最好的。)

验证工作正常,除非我想通过attr_accessorattr_writer重新定义getter / setter。 (我在表单上有虚拟属性需要与验证分开。)为了弄清问题是什么,我使用属性item_length进行了测试。如果我添加attr_accessor :item_length,验证将停止工作。所以,我想问题是如何在不使用点表示法的情况下读取属性的值。由于验证使用字符串,我无法使用正常的阅读方式。

这是一个片段:

if %w(keywords 
      item_length 
      item_length_feet 
      item_length_inches).all?{|attr| read_attribute(attr).blank?}
    errors.add(:base, "Please fill out at least one field")
  end

就像我说的那样,虚拟的attrbutes(length_inches和length_feet)根本不起作用,而且正常的属性(length)有效,除非我重新定义了getter / setter。

2 个答案:

答案 0 :(得分:6)

您应该将read_attribute视为读取Active Record列的私有方法。否则你应该直接使用读者。

self.read_attribute(:item_length) # does not work
self.item_length # ok

由于您尝试动态调用它,因此可以使用泛型ruby方法public_send来调用指定的方法

self.public_send(:item_length) # the same as self.item_length

答案 1 :(得分:6)

如评论中所述,请使用send

array.all? {|attr| send(attr).blank?}

对于那些想知道send在这种情况下是否正常的人,是的是:对象调用自己的实例方法。

但是send是一个很好的工具,因此每当您使用其他对象时,请确保将其公共API用于public_send