Rails vs Join和Union

时间:2018-05-30 21:41:19

标签: ruby-on-rails activerecord

我的activerecord搜索出现问题。我以为我的模型设置正确,但是我的连接很差(不确定连接或联合是否是正确的方法?不应该这么困难)。

我有导游为有start_dates的旅行创建出价。我想创建一个已过期的出价列表(即开始日期是过去的)。如果出价被拒绝,参与者也可以拥有LosingBids

在一个完美的世界中,我会有一个结果集,其中包括失败的出价和该指南的过期出价,但我发现有两个不同的结果集。不幸的是,我无法获得任何“过期的出价”。代码注释中的结果/错误。

class GuidesController < ApplicationController

  def expired_declined

    #this declined_bids call works
    @declined_bids = LosingBid.where("guide_id = ?", current_guide.id.to_s)

    #this expired_bids call returns Trips, not Bids
    @expired_bids = Bid.where("guide_id = ?", current_guide.id.to_s).expired

    #this expired_bids call gives me the following error:
    #SQLite3::SQLException: no such column: trips.start_date: SELECT  1 AS one FROM #”bids" WHERE (guide_id = '1') AND (trips.start_date < '2018-05-30') LIMIT ?
    @expired_bids = Bid.where("guide_id = ?", current_guide.id.to_s).where("trips.start_date < ?", Date.today)
  end
end

class Guide < ApplicationRecord
  has_many :bids
  has_many :losing_bids
end

class Trip < ApplicationRecord
  has_many :bids
end

class Bid < ApplicationRecord
  belongs_to :trip
  belongs_to :guide

  def self.expired
    Trip.where("start_date <= ?", Date.today) #.where("guide_id = ?", current_guide.id.to_s)
  end
end

class LosingBid < ApplicationRecord
  belongs_to :trip
  belongs_to :guide
end

2 个答案:

答案 0 :(得分:0)

Trip.where("start_date <= ?", Date.today).bids会将过期的出价退回给您。

您应该在旅行中移动expired范围,而不是出价。

如果您想在Bid上使用范围,则可以定义。

class Bid
  scope :expired, -> { joins(:trip).where('trips.start_date <= ?', Date.current) }
end

答案 1 :(得分:0)

我真的会怀疑你是否需要一个单独的LosingBid模型,或者只是创建重复和不必要的复杂性。而只需将enum column添加到包含状态的出价:

class Bid
  enum status: [:pending, :declined, :expired, :accepted]
end

这只是一个简单的整数列,用作位掩码。

这将让您通过以下方式查询:

Bid.pending
Bid.expired
Bid.where(status: [:pending, :accepted])
Bid.where.not(status: :accepted)

您可以通过以下方式拒绝出价:

class BidsController
  # PATCH /bids/decline
  def reject
    @bid.declined!
    redirect_to bid, notice: 'Bid declined'
  end
end

然后,您可以设置每天运行一次的计划任务,以自动使任务过期(例如使用whenever gem):

every 1.days do
  runner "BidExpiryService.perform"
end
# app/services/bid_expiry_service.rb
module BidExpiryService
  def self.perform
    bids = Bid.pending
              .joins(:trip)
              .where('trips.start_date <= ?', Date.current)
    bids.update_all(status: Bid.statuses[:expired])
    # @todo notify guides that bid has expired
  end
end