【问题标题】:Rails 4, order in has_many :through. It simply does nothingRails 4,在 has_many 中订购:通过。它什么也不做
【发布时间】:2015-09-25 09:33:45
【问题描述】:

我有这种情况:

class Student < ActiveRecord::Base
    has_many :tickets
    has_many :movies, through: :tickets
end


class Movie < ActiveRecord::Base
    has_many :tickets
    has_many :students, through: :tickets
end


class Ticket < ActiveRecord::Base
    belongs_to :movie, counter_cache: true
    belongs_to :student
end


class Cinema < ActiveRecord::Base
    has_many :movies, dependent: :destroy
    has_many :students, through: :movies
end

我的 (movie_controller.rb) 控制器中有这段代码:

def show
  @tickets = @movie.tickets.includes(:student)
end

现在在我的网格中 (show.html.erb) 我有这种情况:

<% @tickets.each do |ticket| %>
  <tr>
    <td><%= ticket.student.id %></td>
    <td><%= ticket.student.code %></td>
    <td><%= ticket.student.last_name %> <%= ticket.student.first_name %></td>
    <td><%= ticket.hours %></td>
    <td><% if ticket.payed %>Yes<% else %>No<% end %></td>
  </tr>
<% end %>

现在我想按学生的“姓氏,名字”排序,但如果我在控制器中使用此代码:

@tickets = @movie.tickets.includes(:student).order('students.last_name')

在我的控制台中,我有一个这样的 SQL 查询:

"AS t0_r0 .... AS t0_r1 ..."等等……正常吗?

我的逻辑错了吗?

如果我在我的模型中使用这样的代码:

class Movie < ActiveRecord::Base
    has_many :tickets
    has_many :students, -> { order('last_name, first_name') }, through: :tickets
end

没有任何效果。我的列表不是按姓氏和名字排序的,而是按默认 (id) 排序的。

如何做得更好?

更新

我从模型“儿童”变成了“学生”。

【问题讨论】:

  • Children 类应该是 Child 例如'child'.pluralize #=&gt; 'children'; 'children'.pluralize #=&gt; 'children'; 'children'.singularize #=&gt; 'child'。 Rails 从关联名称中推断出类名和表名(使用复数和单数化等方法),因此如果您必须使用子类作为类名,那么您需要告诉关联,例如has_many :childrens, class_name: 'Children'...` 不确定您的表格是什么样的,但您可能还需要添加 primaryforeign 键。
  • 您可以尝试使用reorder('childrens.last_name ASC') 代替您当前的.order() 吗? ; "AS t0_r0 .... AS t0_r1 ..." 是 Rails 为表连接生成的名称(t0_r0 是表 0 行 0 的别名)。在您的 SQL 查询中使用 joins/includes 生成这个是完全正常的
  • @engineersmnky,我用 Children >> Student 编辑了这个问题。

标签: ruby-on-rails ruby performance ruby-on-rails-4 rails-activerecord


【解决方案1】:

""AS t0_r0 .... AS t0_r1 ..." 等等...正常吗?"

是的,包含已作为外连接实现,因此 order by 可以应用于从票证表返回的行。

要为此使用范围,您需要执行类似的操作:

student.rb

def self.by_last_name
  order(:last_name)
end

ticket.rb

def self.by_student_last_name
  joins(:student).merge(Student.by_last_name)
end

...然后...

@tickets = @movie.tickets.by_student_last_name

【讨论】:

  • 是的,但我不喜欢这个查询。有其他选择吗?
  • @JohnSam 你是什么意思“不喜欢这个查询”?您当然可以使用原始 sql 手动创建替代方案,但为什么呢?
  • 对不起。我的意思是:该查询在性能方面是否良好?例如,当门票和儿童是数百人时?我在控制器中使用该代码的逻辑是否正确?在 ActiveRecord 中对这种类型的关系使用查询的正确方法是什么?
  • 1) 是的,这是最佳查询。 2)更是如此,即使它是数百万。 3)您可以改为将其作为模型中的范围。 4) 是的,ActiveRecord 在这里做出了正确的选择。
  • @DavidAldridge,感谢您的回答。您建议如何在模型中创建范围?
猜你喜欢
  • 2017-11-30
  • 2011-01-13
  • 1970-01-01
  • 2014-09-22
  • 1970-01-01
  • 2019-04-18
  • 1970-01-01
  • 1970-01-01
  • 2013-11-24
相关资源
最近更新 更多