Rails:ActiveRecord数据库排序操作不区分大小写

16

我正在学习 Rails(跟随 Coursera 上的 SAAS 课程),并使用 ActiveRecord 处理简单的电影表格。

我想显示所有按标题排序的电影。我希望不区分大小写进行排序。

我尝试了以下方法:

Movie.all(:conditions => ["lower(title) = ?", title.downcase],:order => "title DESC")
=>undefined local variable or method `title' for #<MoviesController:0xb4da9a8>
我认为它不能识别小写的标题。
这是实现不区分大小写排序的最佳方式吗?
谢谢!
4个回答

23

使用 where 而不是 all

Movie.where("lower(title) = ?", title.downcase).order("title DESC")

虽然我不太理解排序的方式。在这里,你将获取所有标题小于等于 title.downcase 的电影。既然都相等了,怎么可以按 title desc 排序呢?

要按照小写标题逆字母顺序对所有电影进行排序:

Movie.order("lower(title) DESC").all

2
在Rails 6中,这将不再被允许,请确保将任何类似于这样的SQL语句包装在Arel.sql()中(https://github.com/rails/rails/commit/310c3a8f2d043f3d00d3f703052a1e160430a2c2) - Nicolas Connault

9
你需要这样做:

你必须执行以下操作:

Movie.order("lower(title) DESC").all

6

更加健壮的解决方案是使用arel节点。我建议在Movie模型上定义几个作用域:

scope :order_by_title, -> {
  order(arel_table['title'].lower.desc)
}

scope :for_title, (title)-> {
  where(arel_table['title'].lower.eq title.downcase)
}

然后调用Movie.for_title(title).order_by_title

与其他列出的答案相比,优点在于.for_title.order_by_title不会因为给title列取别名或者连接到另一个包含title列的表而出错,并且它们是经过SQL转义的。

就像rickypai 提到的那样,如果你没有在这一列上建立索引,数据库将会很慢。但是,复制数据并对另一列应用转换是不好的(正常)形式,因为其中一列可能会与另一列不同步。不幸的是,早期版本的mysql除了触发器之外没有太多替代方案可供选择。在5.7.5之后,您可以使用虚拟生成的列来实现这一点。然后在不区分大小写的情况下,您只需使用生成的列(这实际上使Ruby更加直观)。

Postgres在这方面有更多的灵活性,可以让您在不必引用特殊列的情况下对函数进行索引,或者您可以将该列设置为不区分大小写的列。

谢谢这个回答。在我看来,这是一个被低估的答案。 - Michael Evans

3

每次让MySQL执行大小写操作都是非常昂贵的。

我的建议是有一个"title"列和一个"title_lower"列。这样,您可以轻松地在"title_lower"列上显示和排序不区分大小写的内容,而无需每次排序时让MySQL执行大小写操作。

记得对两个列都建立索引,或者至少对"title_lower"进行索引。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接