RoR - 在构建之前检查记录是否存在

时间:2014-09-03 23:30:13

标签: ruby-on-rails nested-attributes

我有两个型号

Address.rb
  belongs_to :zip
  accepts_nested_attributes_for :zip

Zip.rb
  has_many :addresses

在新地址的表单上我也创建了一个Zip。但我想检查插入的Zip是否已经存在。如果是这样,它应该返回现有的Zip,如果没有,它应该创建一个新的

AddressController
  def new
    @address = Address.new
    @address.build_zip
  end

我在StackOverFlow上看到一个类似的question而没有我正在跳的答案......有人建议:

  before_create :check_zip_exists

  def check_zip_exists
    @zip = Zip.find_by_cp1_and_cp2(self.cp1, self.cp2)
    if @zip!=nil
      #
    end
  end

#应该将现有的Zip与地址相关联而不是创建一个新的?

2 个答案:

答案 0 :(得分:2)

尝试类似:

zip = Zip.where(field: value).first_or_create

<强>更新

当您使用accepts_nested_attributes_for :zip时,内部发生的事情是生成名为zip_attributes=(attributes)的公共方法。

此方法调用私有方法(取决于关系是集合还是单个对象),在您的情况下,调用的私有方法是assign_nested_attributes_for_one_to_one_association

因此,您可以覆盖zip_attributes=(attributes)模型中的public_method Address来替换正常行为:

def zip_attributes=(attributes)
  self.zip = Zip.where(attributes).first_or_create #you can change attributes to be the fields that you need to find the correct zip
end

更新2

def zip_attributes=(attributes)
  cp1 = attributes.delete(:cp1)
  cp2 = attributes.delete(:cp2)
  self.zip = Zip.where(cp1: cp1, cp2: cp2).first_or_create(attributes)
end

答案 1 :(得分:2)

这样做的方式如下:

Address.rb
  belongs_to :zip
  accepts_nested_attributes_for :zip, :reject_if => :check_zip_exists

  private

  def check_zip_exists(attributed)
    cp1 = attributed['cp1']
    cp2 = attributed['cp2']
    zip = Zip.where(:cp1=>cp1, :cp2=>cp2).first
    if zip.nil?
      return false
    else
      self.zip_id = zip.id
    end
  end