【问题标题】:Rails: Polymorphic associations not including proper table aliases in joins?Rails:多态关联不包括连接中的正确表别名?
【发布时间】:2014-12-09 22:25:26
【问题描述】:

我正在尝试通过 :through 和 :source 选项使用两个相似的多态关联进行 sql 搜索。我所看到的是,rails 为第一个“has_many :reservation_trip_itinerary_entries ...”省略了表名别名

额外的问题:是否可以创建一个新的关联或别名来返回一个关联但如果一个为空则恢复为备份?也许这值得另一个问题?

这是行程条目(通过 TripType 和分支 ReservationTrip 到 Reservation 的子项,每个都包含一个单独的列表):

class ItineraryEntry < ActiveRecord::Base

    default_scope order('position ASC')

    attr_accessible :title, :code, :datetime, :position, :itinerary_type, :itinerary_id, :action_type, :action_id
    belongs_to :itinerary, polymorphic: true
    belongs_to :action, polymorphic: true

这是预订(许多 ItineraryEntries 的父项):

class Reservation < ActiveRecord::Base
    has_many :reservation_trips, :order => :departure_date, :dependent => :destroy
    has_many :trip_types, :through => :reservation_trips  # contact booking report                                                                                            
    has_many :reservation_trip_itinerary_entries, :through => :reservation_trips, :source => :itinerary_entries
    has_many :trip_type_itinerary_entries, :through => :trip_types, :source => :itinerary_entries

    # excluded irrelevant methods

    def search

        # many other search params excluded, all populating 'includes' and
        # 'warez' in the same way

        if params.key?(:itinerary_entry) and not params[:itinerary_entry].empty?
            includes.push(:reservation_trip_itinerary_entries)
            includes.push(:trip_type_itinerary_entries)
            warez.push("(                                                                                                                                                         
      (reservation_trip_itinerary_entries.action_type = '#{params[:itinerary_entry][:action_type]}' AND                                                                 
       reservation_trip_itinerary_entries.action_id = #{params[:itinerary_entry][:action_id]})                                                                          
      OR                                                                                                                                                                
      (trip_type_itinerary_entries.action_type = '#{params[:itinerary_entry][:action_type]}' AND                                                                        
       trip_type_itinerary_entries.action_id = #{params[:itinerary_entry][:action_id]})                                                                                 
  )")
        end
        Reservation.includes(includes).where(warez.join(' AND ')).order('reservations.created_at DESC').limit(params[:limit])
    end

这是它正在生成的 sql,但有错误。注意“itinerary_entries”的第一个列表没有别名,而第二个有别名(“trip_type_itinerary_entries_reservations”):

SELECT DISTINCT "reservations".id,
                reservations.created_at AS alias_0
FROM "reservations"
LEFT OUTER JOIN "reservation_trips" ON "reservation_trips"."reservation_id" = "reservations"."id"
LEFT OUTER JOIN "itinerary_entries" ON "itinerary_entries"."itinerary_id" = "reservation_trips"."id"
AND "itinerary_entries"."itinerary_type" = 'ReservationTrip'
LEFT OUTER JOIN "reservation_trips" "reservation_trips_reservations_join" ON "reservation_trips_reservations_join"."reservation_id" = "reservations"."id"
LEFT OUTER JOIN "trip_types" ON "trip_types"."id" = "reservation_trips_reservations_join"."trip_type_id"
LEFT OUTER JOIN "itinerary_entries" "trip_type_itinerary_entries_reservations" ON "trip_type_itinerary_entries_reservations"."itinerary_id" = "trip_types"."id"
AND "trip_type_itinerary_entries_reservations"."itinerary_type" = 'TripType'
WHERE (( (reservation_trip_itinerary_entries.action_type = 'Activity'
          AND reservation_trip_itinerary_entries.action_id = 3)
        OR (trip_type_itinerary_entries.action_type = 'Activity'
            AND trip_type_itinerary_entries.action_id = 3) ))
ORDER BY reservations.created_at DESC LIMIT 100

这是 SQL 错误:

PG::Error: ERROR:  missing FROM-clause entry for table "reservation_trip_itinerary_entries"
LINE 2:           (reservation_trip_itinerary_entries.action_type = ...
                   ^

想法?谢谢!

【问题讨论】:

    标签: sql ruby-on-rails postgresql polymorphic-associations


    【解决方案1】:

    玩了这个之后,我发现 ActiveRecord 在这里有细微差别。它不会为第一个关联分配别名(在原始问题中名为“itinerary_entries”),但会为所有后续关联分配别名。

    所以我通过像这样破解我的 WHERE 子句来得到我的查询:

    if params.key?(:itinerary_entry) and not params[:itinerary_entry].empty?
      includes.push(trip_types: [:itinerary_entries], reservation_trips: [:itinerary_entries])
      warez.push("                                                                                                          
          (itinerary_entries.action_type = '#{params[:itinerary_entry][:action_type]}' AND                                  
           itinerary_entries.action_id = #{params[:itinerary_entry][:action_id]}) OR                                        
          (itinerary_entries_trip_types.action_type = '#{params[:itinerary_entry][:action_type]}' AND                       
           itinerary_entries_trip_types.action_id = #{params[:itinerary_entry][:action_id]})                                
      ")
    end
    

    产生了这个查询

    SELECT DISTINCT "reservations".id, 
                    reservations.created_at AS alias_0 
    FROM   "reservations" 
           LEFT OUTER JOIN "reservation_trips" 
                        ON "reservation_trips"."reservation_id" = 
                           "reservations"."id" 
           LEFT OUTER JOIN "itinerary_entries" 
                        ON "itinerary_entries"."itinerary_id" = 
                           "reservation_trips"."id" 
                           AND "itinerary_entries"."itinerary_type" = 
                               'ReservationTrip' 
           LEFT OUTER JOIN "reservation_trips" "reservation_trips_reservations_join" 
                        ON "reservation_trips_reservations_join"."reservation_id" = 
                           "reservations"."id" 
           LEFT OUTER JOIN "trip_types" 
                        ON "trip_types"."id" = 
           "reservation_trips_reservations_join"."trip_type_id" 
           LEFT OUTER JOIN "itinerary_entries" "itinerary_entries_trip_types" 
                        ON "itinerary_entries_trip_types"."itinerary_id" = 
                           "trip_types"."id" 
                           AND "itinerary_entries_trip_types"."itinerary_type" = 
                               'TripType' 
    WHERE  ( ( itinerary_entries.action_type = 'Activity' 
               AND itinerary_entries.action_id = 3 ) 
              OR ( itinerary_entries_trip_types.action_type = 'Activity' 
                   AND itinerary_entries_trip_types.action_id = 3 ) ) 
    ORDER  BY reservations.created_at DESC 
    LIMIT  100 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-06-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多