【问题标题】:Active Record Filter on Two Models两个模型上的 Active Record 过滤器
【发布时间】:2017-10-04 20:58:41
【问题描述】:

我正在构建一个预订系统,用户可以在其中搜索开放预订。 Reservation 有一个 :on 范围,用于过滤在给定日期和时间预订的预订。仅 Reservations 上的这个过滤器就可以正常工作,但我还想为给定的seating_capacity(客人)向 Table 模型添加一个过滤器,这样我就可以在给定的一天显示与给定的seating_capacity 匹配的所有预订/时间。任何想法如何添加该过滤器?

型号

class Reservation < ApplicationRecord
  belongs_to :user, optional: true
  belongs_to :table, optional: true

  scope :on, -> (day, time) { where('date = ? AND starts_at <= ? AND ends_at > ?', day, time, time)}
end

class Table < ApplicationRecord
  has_many :reservations
  has_many :users, through: :reservations

  def self.free_on(guests, day, time)
    reserved_table_ids = Reservation.on(day, time).pluck('DISTINCT table_id')
    reserved_table_ids ? where.not(id: reserved_table_ids) : all
  end

  def self.reserved_on(guests, day, time)
    reserved_table_ids = Reservation.on(day, time).pluck('DISTINCT table_id')
    where(id: reserved_table_ids)
  end
end

控制器

class TablesController < ApplicationController
  def index
    @reserved_tables = Table.reserved_on(params[:guests], params[:day], params[:time])
    @open_tables = Table.free_on(params[:guests], params[:day], params[:time])
  end
end

查看

<%= form_tag(tables_path, :method => "get", id: "table-search-form") do %>
  <%= text_field_tag :day, params[:day], class:"datepicker", placeholder: "Select Day" %>
  <%= text_field_tag :time, params[:time], class:"timepicker", placeholder: "Select Time" %>
  <%= submit_tag "Search", :name => nil %>
<% end %>

架构

  create_table "reservations", force: :cascade do |t|
    t.integer  "user_id"
    t.integer  "table_id"
    t.datetime "date"
    t.time     "starts_at"
    t.time     "ends_at"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["table_id"], name: "index_reservations_on_table_id", using: :btree
    t.index ["user_id"], name: "index_reservations_on_user_id", using: :btree
  end

  create_table "tables", force: :cascade do |t|
    t.integer  "seating_capacity"
    t.datetime "created_at",       null: false
    t.datetime "updated_at",       null: false
  end

【问题讨论】:

  • 您的处理方式有什么问题?更容易知道具体问题是什么。
  • 我可以根据 :date:starts_at:ends_at 时间过滤预订。但我想添加一个范围,根据它们的:seating_capacity 过滤表并将其链接到 reservation :on 过滤器。这样,我将只获得在所选日期/时间 >= seating_capacity 的表格。

标签: ruby-on-rails rails-activerecord


【解决方案1】:

您可以使用 joins(:table) 来实现座位容量范围,这就是它的外观:

scope :with, -> (capacity) { joins(:table).where(tables: {seating_capacity: capacity}) }

然后您可以像这样查询具体的预订日期、时间和座位容量:

Reservations.on(day, time).with(capacity)

【讨论】:

  • 在此查询中,:with 作用域返回所有 Reservation 与确切的 capacity,但您也可以对更大的 seating_capacity 执行相同操作。这取决于您想要达到的目标。
  • 我试过了,但表格仍然没有在 seating_capacity 上过滤。当查询包含(seating_capacity &gt;= '4') 时,将返回所有表,包括座位数为 2 的表。
  • 那是因为使用的语法不正确。试试这个:joins(:tables).where("tables.seating_capacity &gt;= ?", capacity)
  • :tables 不会加入 Reservation,因为 belongs_to 关系。 :table 将加入,但我在 (table.seating_capacity) 收到 PG::SyntaxError。我不能打电话给seating_capacity...
  • 你是完全正确的,我误读了 db:schema !尝试使用joins(:table)("tables.seating_capacity &gt;= ?", capacity)。表格 - where() 内的复数形式。我很确定这应该可行。如果是这样,我会更新我的答案。
【解决方案2】:

Datagrid 是在页面上轻松添加过滤器的好方法。

https://github.com/bogdan/datagrid

结帐演示:http://datagrid.herokuapp.com/

【讨论】:

    【解决方案3】:

    这里给出了你需要使用join的好例子

    rails scope and joins

    【讨论】:

      【解决方案4】:
      @reservationsWithinInterval1 = Reservation.where('startdate >= ? AND startdate < ? , @reservation.startdate, @reservation.enddate)
      
      @reservationsWithinInterval2 = Reservation.where('enddate >= ? AND enddate < ?, @reservation.startdate, @reservation.enddate)
      

      然后检查是否

        if @reservationsWithinInterval1.count > 0 || @reservationsWithinInterval2.count>0
        flash[:notice] = 'Select different time. Car already reserved in this time'
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-07-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多