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

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

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

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

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

什么好主意吗?


当前回答

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

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

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

其他回答

另一种选择是

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

引用SQLite文档:

任何其他字符匹配自身或 它的小写/大写等价(即。 不区分大小写匹配)

...我不知道。但它是有效的:

sqlite> create table products (name string);
sqlite> insert into products values ("Blue jeans");
sqlite> select * from products where name = 'Blue Jeans';
sqlite> select * from products where name like 'Blue Jeans';
Blue jeans

所以你可以这样做:

name = 'Blue jeans'
if prod = Product.find(:conditions => ['name LIKE ?', name])
    # update product or whatever
else
    prod = Product.create(:name => name)
end

不是#find_or_create,我知道,它可能不是很跨数据库友好,但值得一看?

假设您使用mysql,您可以使用不区分大小写的字段:http://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html

如果您正在使用Postegres和Rails 4+,那么您可以选择使用列类型CITEXT,这将允许不区分大小写的查询,而不必写出查询逻辑。

迁移:

def change
  enable_extension :citext
  change_column :products, :name, :citext
  add_index :products, :name, unique: true # If you want to index the product names
end

为了测试它,你应该期待以下内容:

Product.create! name: 'jOgGers'
=> #<Product id: 1, name: "jOgGers">

Product.find_by(name: 'joggers')
=> #<Product id: 1, name: "jOgGers">

Product.find_by(name: 'JOGGERS')
=> #<Product id: 1, name: "jOgGers">

这里你可能得更啰嗦一些

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