我正在Rails中建立一个具有特定销售模型的商店。我需要允许用户每30天只向其订单添加3个项目。 30天计数器应该在添加第一个order_item时开始。一旦30天到期,用户将能够添加3个订单。如果30天没有通过,例如,用户添加了两个order_items,他仍然可以在30天内再添加一个order_item。 因此,如果用户尝试添加超过3个项目以显示错误消息,并忽略将order_items保存到current_user的订单。
我有产品,订单,order_items,用户。我想我应该向用户模型添加一些内容,但我不确定是什么。
order_items_controller.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
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
order_item.rb
class OrderItem < ActiveRecord::Base
belongs_to :product
belongs_to :order
validates :quantity, presence: true, numericality: { only_integer: true, greater_than: 0 }
validate :product_present
validate :order_present
before_save :finalize
def unit_price
if persisted?
self[:unit_price]
else
product.price
end
end
def total_price
unit_price * quantity
end
private
def product_present
if product.nil?
errors.add(:product, "is not valid or is not active.")
end
end
def order_present
if order.nil?
errors.add(:order, "is not a valid order.")
end
end
def finalize
self[:unit_price] = unit_price
self[:total_price] = quantity * self[:unit_price]
end
end
order.rb
class Order < ActiveRecord::Base
belongs_to :order_status
has_many :order_items
before_create :set_order_status
before_save :update_subtotal
def subtotal
order_items.collect { |oi| oi.valid? ? (oi.quantity * oi.unit_price) : 0 }.sum
end
private
def set_order_status
self.order_status_id = 1
end
def update_subtotal
self[:subtotal] = subtotal
end
end
carts_controller.rb
class CartsController < ApplicationController
def show
@order_items = current_order.order_items
end
的routes.rb
resources :order_items, only: [:create, :update, :destroy, :new]
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>
答案 0 :(得分:2)
我会向用户模型添加begin_date
和order_counter
。每次添加订单时,查看begin_date
是否超过30天,然后将begin_date
设置为实际日期。如果begin_date少于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
在UserController
中添加其他属性,以便在user_params
中允许这些属性。
然后更改OrderItemController
def create
now = Date.today
success = false
if current_user.begin_date && ((now - 30) < current_user.begin_date)
if current_user.order_counter >= 3
# deal with the case that order should not be created,
# for example redirect.
else
current_user.order_counter += 1
current_user.save
success = true
end
else
current_user.order_counter = 1
current_user.begin_date = now
current_user.save
success = true
end
if success
@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
else
respond_to do |format|
format.js { flash[:notice] = "CREATION NOT POSSIBLE." }
end
end
end
您还可以将检查代码放在用户模型中的方法中,这样可以更清晰。
答案 1 :(得分:1)
通常,在某些情况下,如果您不想在rails中创建元素,则应选择通过验证器处理该情况。
你可以在这里采取嵌套方法:
将OrderItem
路线嵌套在Order
下(您可以在Rails Guides about Nested Routing找到有关嵌套的更多信息)
您应首先向first_item_added_at
模型
Order
rails generate migration AddFirstItemAddedAtToOrder
class AddFirstItemAddedAtToOrder < ActiveRecord::Migration
def change
add_column :orders, :first_item_added_at, :date
end
end
嵌套时,您可以通过路径
创建新的OrderItem
POST /orders/:id/order_items
然后,您必须在OrderItem
模型中添加验证器
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
如果你不希望嵌套OrderItem
,那么模型仍然保持不变,但你的控制器看起来像:
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
请注意,我已将current_order.id
添加到您的order_item_params
方法。
编辑:将order_id: current_order.id
替换为order: current_order
,以便在实际保存之前提供与新OrderItem
的关系