I'm building a store in Rails that has a specific sales model. I need to allow a user to add only 3 items to his order per 30 days. The 30 days counter should start upon adding the first order_item. Once 30 days expires, user would be able to add 3 orders. If 30 days didn't pass and for an example, user adds two order_items he would still be allowed to add one more order_item within 30 days. So as well if user tries to add more then 3 items to show an error message and disregard saving of the order_items to current_user's order.
I have products, orders, order_items, users. I guess that I should add something to user model but I'm not sure what.
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>
I would add a begin_date
and a order_counter
to user model. Every time you add an order, look if the begin_date
is more than 30 days ago, then set the begin_date
to the actual date. If the begin_date is less than 30 days ago, increase the counter. And if the counter ist already 3 refuse the order.
You can add the columns to the user table by the command line argument
rails generate migration AddOrderCounterToUser
This will create a class in db/migrations:
class AddPartNumberToProducts < ActiveRecord::Migration
def change
add_column :users, :begin_date, :date
add_column :users, :order_counter, :integer
end
end
Add the additional attributes in your UserController
to permit them in user_params
.
Then change the create method in your 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
You can also put the checking code in a method in the user model, that would be cleaner.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With