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

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

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

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

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

什么好主意吗?


当前回答

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

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

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

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

其他回答

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

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

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

你可以在模型中这样使用

scope :matching, lambda { |search, *cols|
    where cols.flatten.map{|col| User.arel_table[col].matches("%#{search}%") }.inject(:or)
}

用在你喜欢的任何地方

User.matching(params[:search], :mobile_number, :name, :email)

可以通过多个列进行搜索

对于单列搜索,您可以使用这样的方法

User.where(User.arel_table[:column].matches("%#{search}%"))

这是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。

另一种没有人提到的方法是在ActiveRecord::Base中添加不区分大小写的查找器。详情可以在这里找到。这种方法的优点是不必修改每个模型,也不必向所有不区分大小写的查询添加lower()子句,只需使用不同的查找器方法即可。

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

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

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

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