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

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

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

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

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

什么好主意吗?


当前回答

另一种选择是

c = Product.find_by("LOWER(name)= ?", name.downcase)

其他回答

你可能想要使用以下语句:

validates_uniqueness_of :name, :case_sensitive => false

请注意,默认设置是:case_sensitive => false,所以如果你没有改变其他方式,你甚至不需要写这个选项。

欲知详情,请浏览: http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html#method-i-validates_uniqueness_of

你也可以像下面这样使用作用域,把它们放在一个关注点中,并包括在你可能需要的模型中:

作用域:ci_find, lambda{|列,值| where("lower(#{column}) = ?", value.downcase)。第一}

然后像这样使用: 模型。ci_find(“列”、“价值”)

大写字母和小写字母只差一位。最有效的搜索方法是忽略这个位,而不是转换上下位等等。如果使用Oracle,请参见NLS_SORT=BINARY_CI等。

这是Rails中的一个完整设置,供我自己参考。如果这对你也有帮助,我很高兴。

查询:

Product.where("lower(name) = ?", name.downcase).first

验证器:

validates :name, presence: true, uniqueness: {case_sensitive: false}

索引(答案来自Rails/ActiveRecord中不区分大小写的唯一索引?):

execute "CREATE UNIQUE INDEX index_products_on_lower_name ON products USING btree (lower(name));"

我希望有一种更漂亮的方式来完成第一个和最后一个,但话又说回来,Rails和ActiveRecord是开源的,我们不应该抱怨——我们可以自己实现它并发送pull request。

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

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

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

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