如何验证儿童记录的数量?

时间:2015-04-25 17:49:56

标签: ruby-on-rails

我有两个型号的Rails 4应用程序。

class User 
  has_many :bids
end

class Bid
  belongs_to :user
end 

用户每周只能创建一个出价,因此我将以下内容添加到出价表

add_column :bids, :expiry, :datetime, default: DateTime.current.end_of_week

以及投标模型的以下范围

scope :default, -> { order('bids.created_at DESC') }
scope :active, -> { default.where('expiry > ?', Date.today ) }

我现在可以阻止用户在控制器级别创建多个出价,如下所示:

class BidsController
  def new
    if current_user.bids.active.any?
      flash[:notice] = "You already have an active Bid. You can edit it here."
      redirect_to edit_bid_path(current_user.bids.active.last)
    else
      @bid = Bid.new
      respond_with(@bid)
    end
  end
end

但是在模型级别验证这一点的最佳方法是什么?

我一直在尝试设置自定义验证,但我很难看到设置它的最佳方法,以便current_user可用于该方法。另外,我是否在正确的对象中添加错误?

class Bid
  validate :validates_number_of_active_bids
  def validates_number_of_active_bids
    if Bid.active.where(user_id: current_user).any?
      errors.add(:bid, "too much") 
    end
  end 
end

2 个答案:

答案 0 :(得分:0)

这似乎应该在协作者服务对象中。创建一个适当命名的新类(类似于ActiveBid,可能会考虑一下名称)该类将使用current_user进行初始化,并返回有效出价或false。

这限制了这个限制的逻辑到一个地方(也许将来某些计划可以有2个等等。

然后在控制器中执行一个执行此逻辑的before_action。

before_action :enforce_bid_limits, only: [:new, create]

private 

def enforce_bid_limits
  active_bid = ActiveBid.new(current_user).call
  if active_bid #returns false or the record of the current_bid
    flash[:notice] = "You already have an active Bid. You can edit it here."
    redirect_to edit_bid_path(bid)
  end
end

稍后,如果您最终需要在多个位置使用此逻辑,请将此内容放入模块中,然后您可以将其包含在所需的控制器中。

答案 1 :(得分:0)

为了保持关注点的分离,请将current_user知识保留在模型层之外。您的出价模型已具有user_id属性。另外,我会添加一个错误,因为验证不会检查出价的“出价”属性,而是整个出价可能无效。

class Bid
  validate :validates_number_of_active_bids
  def validates_number_of_active_bids
    if Bid.where(user_id: user_id).active.any?
      errors[:base] << "A new bid cannot be created until the current one expires"
    end
  end 
end