为什么我的Rails应用程序中的字母顺序会中断?

时间:2018-03-24 18:11:02

标签: ruby-on-rails

我有一个非常简单的rails页面,显示“项目”,其中包含标题,年份和与之关联的文件。这是我的控制器:

# GET /projects
# GET /projects.json
def index
  @projects = Project.all.order(:title)
end

这是index.html.erb:

<ul>
  <% @projects.each do |project| %>
    <li><a href="<%= project.document.url %>" target="_blank"><em><%= project.title %></em>, <%= project.year %></a>
      <% if logged_in? %>
       <br><%= link_to 'Edit', edit_project_path(project) %> / <%= link_to 'Destroy', project, method: :delete, data: { confirm: 'Are you sure?' } %>
      <% end %>
    </li>
  <% end %>
  <% if logged_in? %>
  <li><%= link_to 'New Project', new_project_path %><p id="notice"><%= notice %></p></li>
<% end %>
</ul>

在Heroku上使用psql(10.3,服务器9.6.2)

除了名为“Spring House”,“Springg House”,Springgg House,等等的所有结果之外,所有结果都按字母顺序完美排序。其他使用此模式的标题排序正确,但出于某种原因, “春天”没有。

Screenshot of Rails app demonstrating incorrect order

对于我应该在应用中查找的内容,您有什么建议吗?

感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

这是一个&#34;功能&#34; Postgresql如何处理排序 - 更糟糕的是,它因数据库而异,甚至从平台到平台。

当您编写Project.all.order(:title)时,Rails会生成SQL(正如您在上面的评论中正确指出的那样),如下所示:

SELECT "projects".* FROM "projects" ORDER BY "projects"."title" ASC

这会留下Postgresql或您正在使用的任何其他数据库来确定订单。 Postgresql使用collations来确定顺序,这是依赖于语言环境的。通过在\l中执行psql命令,可以查看数据库正在使用的归类。例如,在我的机器上,我的数据库默认为en_US.UTF-8

这里变得棘手。我在postgres中创建了一个表格如下:

CREATE TABLE sorttest (name text);
INSERT INTO sorttest VALUES ('Spring House');
INSERT INTO sorttest VALUES ('Springg House');
INSERT INTO sorttest VALUES ('Springgg House');
SELECT * FROM sorttest ORDER BY name ASC;

在我的Mac(Mac OS 10.13.3)上,它返回

name      
----------------
Spring House
Springg House
Springgg House

然而,在我的Debian机器上,它返回

name      
----------------
Springgg House
Springg House
Spring House

据我所知,Mac实际上是#34;做错了#34;虽然它是你想要的结果。我的Debian盒子和你的Heroku dyno按照UTF-8规范排序:忽略空格和大小写,&#34; springgghouse&#34;应该来到#spring;&#34;。

如果要使用其他排序规则进行排序(例如,&#34; C&#34;或&#34; POSIX&#34;排序规则),则需要使用如下SQL命令:

SELECT "projects".* FROM "projects" ORDER BY "projects"."title" COLLATE "C" ASC

幸运的是,你可以使用ActiveRecord实现目标:

Project.all.order('title COLLATE "C"')

但是,请注意,这将使您的排序顺序成为大写字母 - &#34; C&#34; collat​​ion比较ASCII字节值,因此大写字母将在小写字母之前排序,例如:

SELECT * FROM sorttest ORDER BY name COLLATE "C" ASC;

name      
----------------
Spring House
SpringGg House
Springg House