我的产品型号包含一些项目

 Product.first
 => #<Product id: 10, name: "Blue jeans" >

我现在从另一个数据集导入一些产品参数,但是名称的拼写不一致。例如,在另一个数据集中,Blue jeans可以拼写为Blue jeans。

我想要产品。find_or_create_by_name("Blue Jeans"),但这将创建一个与第一个几乎相同的新产品。我的选择是什么,如果我想找到和比较小写的名字。

性能问题在这里并不重要:只有100-200个产品,我希望将其作为导入数据的迁移来运行。

什么好主意吗?


当前回答

不区分大小写的搜索是Rails内置的。它解释了数据库实现的差异。使用内置的Arel库,或者像Squeel这样的宝石。

其他回答

有些人使用LIKE或ILIKE显示,但这些允许正则表达式搜索。在Ruby中你也不需要小写。您可以让数据库为您做这件事。我想可能会快一些。first_or_create也可以用在where后面。

# app/models/product.rb
class Product < ActiveRecord::Base

  # case insensitive name
  def self.ci_name(text)
    where("lower(name) = lower(?)", text)
  end
end

# first_or_create can be used after a where clause
Product.ci_name("Blue Jeans").first_or_create
# Product Load (1.2ms)  SELECT  "products".* FROM "products"  WHERE (lower(name) = lower('Blue Jeans'))  ORDER BY "products"."id" ASC LIMIT 1
# => #<Product id: 1, name: "Blue jeans", created_at: "2016-03-27 01:41:45", updated_at: "2016-03-27 01:41:45"> 

这里你可能得更啰嗦一些

name = "Blue Jeans"
model = Product.where('lower(name) = ?', name.downcase).first 
model ||= Product.create(:name => name)

有几个注释提到了Arel,但没有提供示例。

下面是一个不区分大小写搜索的Arel示例:

Product.where(Product.arel_table[:name].matches('Blue Jeans'))

这种类型的解决方案的优点是它与数据库无关——它将为当前适配器使用正确的SQL命令(匹配将对Postgres使用ILIKE,而对其他一切使用LIKE)。

如果您正在使用postgres(可能是其他的),我喜欢这个解决方案。

Product.find_by("name ilike 'bLue JEaNS'")

我更喜欢这个,有几个原因。

更清晰的连接到数据库操作->你可以复制粘贴到哪里… 如果您选择添加一个外接符%,这很简单。

在postgres:

 user = User.find(:first, :conditions => ['username ~* ?', "regedarek"])