Rails以及如何使子选择选择ID

时间:2012-06-21 18:17:19

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

我是Rails的新手,我知道这是一个简单的问题,但它让我发疯。 我的应用程序是使用Ruby 1.9.2和Rails 3.1构建的。 我正在编写一个应用程序来管理类似酒店的房间预订。 所以这堂课代表住宿:

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解决了这个问题。我在下面的评论中写了解决方案

3 个答案:

答案 0 :(得分: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

答案 1 :(得分: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)

答案 2 :(得分:0)

最后我找到了Arel的解决方案:

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]) ))