2013-03-26 49 views
0

使用Rails 3.2。假設我想要2個選項:Ruby on Rails中更好的遞歸循環

  1. 獲取所有旅行照片。
  2. 獲取第一張旅行照片。

我有以下代碼:

# trip.rb 
class Trip < ActiveRecord::Base 
    has_many :trip_days 

    def trip_photos 
    if (photos = trip_days.map(&:spots).flatten.map(&:photos).flatten.map) 
     photos.each do |photo| 
     photo.url(:picture_preview) 
     end 
    end 
    end 

    def trip_photo 
    trip_photos.first 
    end 
end 

# trip_day.rb 
class TripDay < ActiveRecord::Base 
    belongs_to :trip 
    has_many :trip_day_spots 
    has_many :spots, :through => :trip_day_spots 
end 

# trip_day_spot.rb 
class TripDaySpot < ActiveRecord::Base 
    belongs_to :trip_day 
    belongs_to :spot 
end 

#spot.rb 
class Spot < ActiveRecord::Base 
end 

# trips_controller.rb 
class TripsController < ApplicationController 
    def index  
    @trips = Trip.public.paginate(:page => params[:page], :per_page => 25) 
    end 
end 

正如所料,trip_photos方法會產生大量的SQL查詢。我想知道有沒有更好的方法來做到這一點?

回答

0

的代碼工作正常,但對急於負載,只需添加:include

# trips_controller.rb 
class TripsController < ApplicationController 
    def index  
    @trips = Trip.public.paginate(:include => [:trip_days => [:spots => :photos]], :page => params[:page], :per_page => 25) 
    end 
end 
0

這是因爲N + 1個查詢。在這種情況下,我們需要加載基礎對象的所有關聯,以便在您調用其關聯對象時,不會觸發任何查詢來獲取它們,只需從它的緩存對象中獲取它們即可。

希望這會工作,但沒有測試。我假設並編寫了以下查詢。

def trip_photos 
    user_trip_days = trip_days.includes(:spots => :photos) 
    photos = user_trip_days.collect {|trip_day| trip_day.spots.map(&:photos).flatten}.flatten 
    photos.each do |photo| 
    photo.url(:picture_preview) 
    end if photos 
end 

讓我知道你是否有任何錯誤。

有關在ActiveRecord的預先加載相關對象的詳細信息,請通過

Guides for RailsRails castRails Tips

+0

感謝。當我通過'trip_photos'運行'trip_photo'時,我有'''的東西,但沒有時間去修復它,因爲我要出門。它應該返回'.url(:picture_preview'。 – Victor 2013-03-26 23:59:13

0

這可能不是最導軌-Y的方式,但如果你真的想要得到的所有一重擊點,你可以這樣做:

def spots 
Spot.joins("join trip_days_spots on spots.id = trip_days_spots.spot_id join trip_days on trip_days.id = trip_days_spots.trip_day_id join trips on trips.id = trip_days.trip_id").where("trips.id = ?", self.id) 
end 

那麼你的循環更改爲:

def trip_photos 
    spots.map(&:photos).flatten.each do |photo| 
    photo.url(:picture_preview) 
    end 
end