2012-06-21 48 views
0

我是Rails的新手,我知道這是一個簡單的問題,但它讓我發瘋。 我的應用程序是用Ruby 1.9.2和Rails 3.1構建的。 我正在寫一個應用程序來管理酒店式的房間預訂。 所以這個類代表住宿:Rails和如何使子選擇ids

class Accommodation < ActiveRecord::Base 
    has_many :reservations, :dependent => :destroy 
end 

而這一次的保留:

class Reservation < ActiveRecord::Base 
    belongs_to :accommodation 
end 

預訂確實有一個名爲accommodation_id場,其中住宿的ID存儲

現在我必須在給定的日期範圍內檢查可用住宿,所以我寫了這種方法:

def self.check_availability(params) 
    # This return the unavailables accommodations 
    ids_to_exclude = Reservation.select(:accommodation_id).where('start_date < ? AND end_date > ?', params[:reservation_end_date], params[:reservation_start_date]) 

    # HERE IS THE PROBLEM 
    accommodations = Accommodation.where("id NOT IN (?)", ids_to_exclude) 

    accommodations 
    end 

第一個查詢作品,但第二個回報:

SELECT `accommodations`.* FROM `accommodation` WHERE (id NOT IN (NULL)) 

,我試圖輸出ids_to_exclude,而不是NULL

我究竟做錯了什麼?

更新:

我用Arel解決了這個問題。我寫了下面

回答

0

ids_to_exclude需要的ID被提取

嘗試在評論該解決方案

reservations_to_exclude = Reservation.select(:accommodation_id).where('start_date < ? AND end_date > ?', params[:reservation_end_date], params[:reservation_start_date]) 

reservations_to_exclude.each do |r| 
    ids_to_exclude << r.accommodation_id 
end 
+0

感謝您的回覆,但是我發現Arel避免了'每個do'塊的解決方案 –

0

你並不需要做兩個數據庫的訪問對於你或許應該讓一個範圍,而你在那裏。另外,我會打電話給路過params到模型的方法不好的形式,你應該更明確一些參數使事情更容易理解和維護:

class Accommodation < ActiveRecord::Base 
    def self.available_between(start_date, end_date) 
     joins(:reservations).where('reservations.start_date >= ? and reservations.end_date <= ?', end_date, start_date) 
    end 
end 

那麼你可以說這事:

all_available = Accommodation.available_between(params[:reservation_start_date], params[:reservation_end_date]).all 

或本:

some = Accommodation.available_between(params[:reservation_start_date], params[:reservation_end_date]) 
        .where(some_other_conditions) 
        .limit(10) 
        .order(:price) 
+0

我首先想到了加入,但是由於在連接上保留了NULL,我放棄了這個想法。我剛剛嘗試過你的方法,因爲它構建了一個內部連接,所以沒有任何結果,所以沒有保留的Accoomodation不會出現 –

+0

@DrDuke:你可以'連接('...'外部連接保留'手動強制LEFT JOIN,並在'where'條件下添加'reservations.id爲null'。 –

+0

是的,你是對的:我可以手動強制加入,但我正在尋找一些東西,而不用手動強制,也不用'to_sql'。無論如何,謝謝:) –

0

最後我發現阿雷爾解決方案:

reservations = Reservation.arel_table 

available_rooms = Accommodation.where(:id => reservations.project(:accommodation_id) 
     .where(reservations[:start_date].lt(params[:reservation_end_date])) 
     .where(reservations[:end_date].gt(params[:reservation_start_date]))) 
+0

這不會工作,因爲我需要其ID不在子查詢中的住宿。試圖調整查詢我有一個錯誤說:'不能訪問Arel :: SelectManager' –