Ruby on rails 如何限制当前用户在每个时间段向订单添加3个以上的订单项目?

Ruby on rails 如何限制当前用户在每个时间段向订单添加3个以上的订单项目?,ruby-on-rails,ruby,model-view-controller,Ruby On Rails,Ruby,Model View Controller,我正在Rails中建立一个具有特定销售模式的商店。我需要允许用户每30天只向其订单添加3项。30天计数器应在添加第一个订单项目时启动。一旦30天到期,用户将能够添加3个订单。如果30天没有过去,例如,用户添加了两个订单项目,他仍然可以在30天内再添加一个订单项目。 所以,若用户试图添加3个以上的项目以显示错误消息,并忽略将订单项目保存到当前用户的订单中,也是如此 我有产品、订单、订单项、用户。我想我应该在用户模型中添加一些东西,但我不确定是什么 订单项目控制器.rb def create

我正在Rails中建立一个具有特定销售模式的商店。我需要允许用户每30天只向其订单添加3项。30天计数器应在添加第一个订单项目时启动。一旦30天到期,用户将能够添加3个订单。如果30天没有过去,例如,用户添加了两个订单项目,他仍然可以在30天内再添加一个订单项目。 所以,若用户试图添加3个以上的项目以显示错误消息,并忽略将订单项目保存到当前用户的订单中,也是如此

我有产品、订单、订单项、用户。我想我应该在用户模型中添加一些东西,但我不确定是什么

订单项目控制器.rb

def create
    @order = current_order
    @order_item = @order.order_items.new(order_item_params)
    @order.user_id = current_user.id
    @order.save
    session[:order_id] = @order.id

  respond_to do |format|
    format.js { flash[:notice] = "ORDER HAS BEEN CREATED." } 
  end
  end
private
  def order_item_params
    params.require(:order_item).permit(:quantity, :product_id, :user_id)
  end
end
class CartsController < ApplicationController
  def show
    @order_items = current_order.order_items
  end
user.rb

class User < ActiveRecord::Base
  has_many :identities, dependent: :destroy
  has_many :order
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :omniauthable, :invitable, :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable
end
form.html.erb

<%= form_for OrderItem.new,  html: {class: "add-to-cart"}, remote: true do |f| %>


        <div class="input-group">
          <%= f.hidden_field :quantity, value: 1, min: 1 %>
          <div class="input-group-btn">
            <%= f.hidden_field :product_id, value: product.id %>
            <%= f.submit "Add to Cart", data: { confirm: 'Are you sure that you want to order this item for current month?'}, class: "btn btn-default black-background white" %>
          </div>
        </div>
      <% end %>
    </div>

我会在用户模型中添加一个
开始日期
和一个
订单计数器
。每次添加订单时,查看
开始日期是否超过30天,然后将
开始日期设置为实际日期。如果开始日期少于30天前,则增加计数器。如果柜台上已经有3位顾客,请拒绝订单

可以通过命令行参数将列添加到用户表中

rails generate migration AddOrderCounterToUser
这将在db/migrations中创建一个类:

class AddPartNumberToProducts < ActiveRecord::Migration
  def change
    add_column :users, :begin_date, :date
    add_column :users, :order_counter, :integer 
  end
end

您还可以将检查代码放在用户模型中的方法中,这样会更干净。

通常,在某些情况下,当您不想在rails中创建元素时,您应该选择通过验证器来处理这种情况

您可以在此处使用嵌套方法: 将您的
OrderItem
路由嵌套在
Order
下(您可以在中找到有关嵌套的更多信息)

首先,您应该向您的
Order
模型添加一个新的数据库列
first\u item\u added\u at

rails generate migration AddFirstItemAddedAtToOrder

class AddFirstItemAddedAtToOrder < ActiveRecord::Migration
  def change
    add_column :orders, :first_item_added_at, :date
  end 
 end
class OrderItem < ActiveRecord::Base
    validate :only_3_items_in_30_days


  private

  def only_3_items_in_30_days
    now = Date.new
    days_since_first = now - order.first_item_added_at

    if order.order_items.count > 2 && days_since_first < 30
      errors.add(:base, 'only 3 items in 30 days are allowed')
    end
    true      # this is to make sure the validation chain is not broken in case the check fails
  end
end
然后,您必须向
OrderItem
模型添加一个验证器

rails generate migration AddFirstItemAddedAtToOrder

class AddFirstItemAddedAtToOrder < ActiveRecord::Migration
  def change
    add_column :orders, :first_item_added_at, :date
  end 
 end
class OrderItem < ActiveRecord::Base
    validate :only_3_items_in_30_days


  private

  def only_3_items_in_30_days
    now = Date.new
    days_since_first = now - order.first_item_added_at

    if order.order_items.count > 2 && days_since_first < 30
      errors.add(:base, 'only 3 items in 30 days are allowed')
    end
    true      # this is to make sure the validation chain is not broken in case the check fails
  end
end
请注意,我已将
当前订单.id
添加到您的
订单项目参数
方法中


编辑:将
order\u id:current\u order.id
替换为
order:current\u order
,以提供新的
OrderItem
在实际保存之前的关系

当我尝试向order:ArgumentError添加项目时,我在终端中遇到此错误(日期与否的比较失败):app/controllers/order\u items\u controller.rb:4:in
我已经更新了我的答案,并添加了一个检查begin\u date是否为Nil(在这种情况下,您必须设置begin\u date,所以在else情况下继续)你是否添加了一个错误处理重定向到另一个页面?我已经更新了你不需要重定向的帖子。接受这个答案。艾琳已经为你写了几乎所有的代码:P你也应该发送一瓶苏格兰威士忌。我收到一个错误:NoMethodError(未定义的方法
第一项\u添加了\u at'for nil:NilClass):app/models/order\u item.rb:46:in
仅\u 3\u items\u in 30\u days'app/controllers/order\u items\u controller.rb:6:in“create”中的原因可能取决于您选择的控制器解决方案。你是采用嵌套方法还是其他方法?在这两种情况下,第一个问题是:在调用
orderitemscocontroller
时,添加项的顺序是否已持久化?第二件事可能是我弄错了两个对象之间的关系是由ActiveRecord生成的时刻。这里的解决方案取决于您选择的控制器版本。我已经更新了第二个示例中的
order\u item\u params
方法。我正在使用您提到的第二个方法,但没有嵌套,我更改了参数,但现在是错误:ActionController::RoutingError(OrderItemsController:Class的未定义局部变量或方法
current\u order):app/controllers/order\u items\u controller.rb:15:in
“app/controllers/order\u items\u controller.rb:1:in`“Cdu”请用完整的控制器代码更新您的初始帖子?看起来,它不再包含方法
当前\u顺序
rails generate migration AddFirstItemAddedAtToOrder

class AddFirstItemAddedAtToOrder < ActiveRecord::Migration
  def change
    add_column :orders, :first_item_added_at, :date
  end 
 end
POST /orders/:id/order_items
class OrderItem < ActiveRecord::Base
    validate :only_3_items_in_30_days


  private

  def only_3_items_in_30_days
    now = Date.new
    days_since_first = now - order.first_item_added_at

    if order.order_items.count > 2 && days_since_first < 30
      errors.add(:base, 'only 3 items in 30 days are allowed')
    end
    true      # this is to make sure the validation chain is not broken in case the check fails
  end
end
def create
  @item = OrderItem.new(item_params)
  if @item.save
     render <whatever_you_want_to_render>
  else
    # @item will contain the errors set in the model's validator
    render <error_reaction>
  end
end

private

def item_params
  params.require(:order_item).permit(
    :attribute_1,
    :attribute_2,
    :order_id       # << this one is very important
  )
end
def create
  @item = OrderItem.new(order_item_params)
  session[:order_id] = current_order.id

  if @item.save
    respond_to do |format|
      format.js { flash[:notice] = "ORDER HAS BEEN CREATED." } 
    end
  else
    render <handling for error>
  end 
end

private
def order_item_params
  base_params = params.require(:order_item)
                      .permit(:quantity, :product_id, :user_id)
  base_params.merge(order: current_order)
 end