0

Railsの使用3.2。2つのオプションが必要だとしましょう:

  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クエリを生成します。それを行うためのより良い方法があるのだろうか?

4

3 に答える 3

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での関連オブジェクトの積極的な読み込みの詳細については、

RailsとRailsキャストのガイドRailsのヒント

于 2013-03-26T17:29:52.357 に答える
0

これはほとんどのレールのような方法ではないかもしれませんが、本当にすべてのスポットを1回のヒットで取得したい場合は、次のようにすることができます。

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
于 2013-03-26T18:11:41.383 に答える
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
于 2013-03-27T15:57:37.193 に答える