如何使用/ join修改复杂的sql查询到rails 3

时间:2010-10-08 09:39:25

标签: ruby-on-rails activerecord mysql ruby-on-rails-3

我正在开发一个汽车共享应用程序,用户可以在其中添加升降机,并且可以为每个升降机选择多个停靠点(通过c,d,e从A到B)。现在,当用户在数据库中搜索电梯时,结果还应包括“A到d”,“c到B”或“c到e”等升降机。

我使用下面的代码使用Rails 2.3.5,但很难将其移植到Rails 3.我确信必须有一种更清晰的方法来实现我正在尝试做的并将一些代码移动到模型。< / p> 如果有人可以帮我解决这个问题,那将会很棒。

class Lift < ActiveRecord::Base
  has_many :stops
end

class Stop < ActiveRecord::Base           
  belongs_to :lift
  belongs_to :city  
end

class City < ActiveRecord::Base
  has_one :stop
end


@lifts = Lift.find(
  :select =>     "lifts.id, bs.city_id as start_city_id, bs2.city_id as destination_city_id",
  :from =>       "lifts",
  :joins =>      "LEFT JOIN stops bs ON lifts.id = bs.lift_id
                  LEFT JOIN stops bs2 ON lifts.id = bs2.lift_id
                  JOIN cities bc ON bs.city_id = bc.id
                  JOIN cities bc2 ON bs2.city_id = bc2.id",
  :include =>    [:stops, :cities],
  :conditions => "bs.lift_id = bs2.lift_id AND bs.position < bs2.position"
                  #uses the position attribute to determine the order of the stops
)

2 个答案:

答案 0 :(得分:0)

我知道这是一个非常简单的答案,但为什么不用这些选项在模型中创建一个范围?

答案 1 :(得分:0)

我有点困惑你正在使用find的:select和:include选项。我知道一个事实:当你使用时忽略select:include(想想有一个插件来修复它)。此外,您还包括:城市,这种关系不会出现在您的代码中。

无论如何,如果您想要为Lift模型添加一些范围,我会考虑切换到Arel API,这是Rails 3中的首选方法。http://m.onkey.org/2010/1/22/active-record-query-interface

你可以将整个查询填充到一个范围内(不要认为你需要:from选项 - 可能是错误的):

class Lift
...
  scope :with_all_stops, select('lifts.id, bs.city_id as start_city_id, bs2.city_id as destination_city_id').\
                         joins('LEFT JOIN stops bs ON lifts.id = bs.lift_id ' +
                               'LEFT JOIN stops bs2 ON lifts.id = bs2.lift_id ' +
                               'JOIN cities bc ON bs.city_id = bc.id ' +
                               'JOIN cities bc2 ON bs2.city_id = bc2.id').\
                         includes(:stops, :cities).\
                         where('bs.lift_id = bs2.lift_id AND bs.position < bs2.position')
...
end

然后只需调用Lift.with_all_stops。或者您可以根据自己的条件进行链接:Lift.with_all_stops.where('cities.name =“Topeka”')。它真的很强大。

如果该查询的某些部分本身有用(在这种特殊情况下可疑),您可以将它们分解到自己的范围中,然后在调用时将它们全部链接在一起。或者将它们链接在 in 另一个范围内,然后调用它。就像我说的,Arel真的很强大。