Rails在find_or_create之前规范化

时间:2014-11-11 01:02:17

标签: ruby-on-rails activerecord

我的模型的地址字段需要是唯一的:

class AddressMeta < AR::Base
  def normalize
    # normalize and store full_address
  end

  validates_uniqueness_of :full_address

  after_validation :normalize
end

我通过地理编码API传递地址,以确保它们在存储之前有效并规范化。我遇到的麻烦是我还希望地址是唯一的,因此每个唯一的地址字符串只有一条记录。请访问以下地址:

101 E 1st St #101, Austin, TX
101 E 1st Street Suite 101, Austin, TX

这两个显然是相同的地址,但我无法在数据库中找到第二个,除非它首先被标准化以匹配第一个。因此,如果存在第一个并且我在第二个上运行find_or_create_by(full_address: address)调用,我最终会错过搜索并创建一个新对象,这会导致冲突。

所以 - 我的问题。在Rails / AR中,如何在执行搜索之前规范化find_or_create_by方法的输入?或者有一种更好的方法来处理在标准化字段后我在一个唯一字段上发生碰撞的情况吗?

1 个答案:

答案 0 :(得分:0)

如果没有代码的完整上下文,很难确定,但是一个解决方案是将规范化执行更改为验证之前而不是之后:

class AddressMeta < AR::Base
  validates_uniqueness_of :full_address

  before_validation do
    full_address = normalize_address(full_address)
  end

  private
  def normalize_address(address_string)
    # Code to convert address with API
    # Returns normalized address string
  end
end

这样唯一性验证器应该有效。另外,一个不错的小重构就是将地址规范化逻辑提取到它自己的类中:

# lib/address_converter.rb
class AddressConverter
  class << self
    def normalize(raw_address)
      # Logic and API Code
      # Returns normalized string
    end
  end
end

# app/models/address_meta.rb
require 'address_converter'

class AddressMeta < AR::Base
  validates_uniqueness_of :full_address

  before_validation do
    full_address = AddressConverter::normalize(full_address)
  end
end