6

我正在将现有的 Rails 3.2 应用程序升级到 4.0。不过,我碰到了一堵砖墙。

我有三个模型,客户端、站点和联系人。站点是属于一个客户端的物理位置,一个客户端可以有多个站点。联系人是属于一个或多个站点的人。因此,客户可以通过站点拥有许多联系人。

客户:

class Client < ActiveRecord::Base

  has_many :sites, -> { where(:sites => {:deleted => false}).order(:name => :asc) }, :dependent => :destroy
  has_many :contacts, -> { order(:lastname => :asc) }, :through => :sites

end

网站:

class Site < ActiveRecord::Base

  belongs_to :client
  has_and_belongs_to_many :contacts

end

联系人:

class Contact < ActiveRecord::Base

  has_and_belongs_to_many :sites

end

问题是当我使用时Client.find(1).contacts,我得到一个ActiveRecord::StatementInvalid异常:

Mysql2::Error: 'order clause' 中的未知列 'contacts.name': SELECT contacts.* FROM contactsINNER JOIN contacts_sitesON contactsid= contacts_sites。内部contact_id加入。= 。在哪里。= 5 和。= 0 排序方式。ASC ,。ASCsitescontacts_sitessite_idsitesidsitesclient_idsitesdeletedcontactslastnamecontactsname

问题是:我不知道它ORDER BY ... `contacts`.`name` ASC是从哪里来的。Contacts 表没有名称列,但 Rails 正在尝试使用它进行排序,但我不知道它来自哪里或如何删除它。这ORDER BY `contacts`.`lastname` ASC很容易;它来自客户端模型。

这些关系在 3.2 中完美运行,但现在在 4.0 中抛出此异常。

更新: 有人指出,额外ORDER BY ... `contacts`.`name` ASC的来自has_many客户端模型中的第一个。但是,其目的是对站点进行排序,而不是对联系人进行排序。我尝试将其更改为.order('sites.name' => :asc)SQL 抱怨没有名为sites.sites.name. 因此,似乎在使用:through =>with时has_many, order 子句被破坏了。

我尝试在站点模型中删除.order()和使用default_scope -> { order(:name => :asc) },但得到的错误与最初报告的完全相同。

4

2 回答 2

9

解决方案很简单。我没有使用.order(:column_name => :asc),而是将其更改为.order('column_name ASC')并且错误消失了,产生了预期的结果。我最初有后者,但在我的 Rails 3 -> 4 升级中实现了前者,并在 RailsCasts 和其他文档中看到了这样的约定。

.joins()正如我后来发现的,这在使用连接表列和按连接表列排序时也是必要的。这是有道理的,因为关联也使用连接。

于 2013-07-16T21:40:49.113 回答
1

你一定累了,就在你的第二行(Client模型),你有order(:name=> :asc),应该是:

class Client < ActiveRecord::Base

  has_many :sites, -> { where(:sites => {:deleted => false}).order(:lastname => :asc) }, :dependent => :destroy
  has_many :contacts, -> { order(:lastname => :asc) }, :through => :sites

end
于 2013-06-28T17:39:53.753 回答