验证可选的虚拟属性

时间:2018-02-03 19:29:43

标签: ruby-on-rails

我正在建立一个谱系应用程序,它将采用动物的名字并将其插入到动物模型中。需要鼓励添加动物的父母,但不是必需的。例如,当您回过头谱时,我们会丢失有关谁生成谁的信息。我将父母的名字作为虚拟属性,通过他们的名字而不是模型中的animal_id搜索其他动物,因为animal_id没有人会引用其他动物,而是以他们的名字命名。但是,如果有人输入虚假的动物名称,那么我需要将该更新无效。

我的虚拟属性是这样的......

def mother_name=(name)
    record = animals.find_by(name: name)
    if(record)
        self.mother = record
    else
        self.errors.add(:mother, "does not exist in database. Add her before this animal")
    end
end

def mother_name
    mother_name
end

当我使用控制台并将母亲的名字改为虚假时,则会正确填充错误属性。当我在对象上执行valid?时,它会返回true,并且errors.messages已被刷新。我需要一种方法让它以虚假的方式返回并保持errors.messages完好无损。

我还添加了一个validates函数来查看母亲的名字是否在模型中,但是当validates运行时,我得到一个错误,说nil没有属性叫mother_name。另外,做两个find_by似乎有点黑客。

同样,我希望母亲和父亲的名字是可选的,因为我们可能没有父母为前几代人的记录 - 但是如果给出,则需要是正确的。

1 个答案:

答案 0 :(得分:2)

我会通过适当的轨道验证来做到这一点,即

class Animal < ApplicationRecord
  attr_accessor :mother_name

  validate :mother_name_valid

  private

  def mother_name_valid
    mother = Animal.find_by(name: mother_name)

    if mother_name.present? && mother.nil?
      self.errors.add(:mother_name, "does not exist in database. Add her before this animal")
    elsif mother.present?
      self.mother = mother
    end         
  end
end

希望这会对你有所帮助。或者你可以写

class Animal < ApplicationRecord
  attr_accessor :mother_name

  validate :mother_name_valid, if: proc { |animal| animal.mother_name.present? }

  private

  def mother_name_valid
    mother = Animal.find_by(name: mother_name)

    if mother.nil?
      self.errors.add(:mother_name, "does not exist in database. Add her before this animal")
    else
      self.mother = mother
    end
  end
end

if proc