ruby on rails - How to make data saved in database expire after a time period? -
i'm building store in rails. store has orders, order_items, users..
right when customer adds order_item cart, order unique id created automatically, , order_items saved under order_items model. there validation saying 3 order_items allowed in 1 order.
if possible, remove order_items saved model after 30 days. 30 days counter should start after saving 3 order_items.
how can achieve this?
thanks
class order < activerecord::base belongs_to :order_status belongs_to :user has_many :order_items validates_length_of :order_items, maximum: 3 #only 3 order_items allowed within order each user 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
order_item.rb
class orderitem < activerecord::base belongs_to :product belongs_to :order validates_associated :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 not active.") end end def order_present if order.nil? errors.add(:order, "is not valid order.") end end def finalize self[:unit_price] = unit_price self[:total_price] = quantity * self[:unit_price] end end
order_items_controller.rb
class orderitemscontroller < applicationcontroller 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 |format| format.js { flash[:notice] = "order has been created." } end end def update @order = current_order @order_item = @order.order_items.find(params[:id]) @order_item.update_attributes(order_item_params) @order_items = @order.order_items end def destroy @order = current_order @order_item = @order.order_items.find(params[:id]) @order_item.destroy @order_items = @order.order_items end private def order_item_params params.require(:order_item).permit(:quantity, :product_id, :user_id) end end
schema.rb
create_table "order_items", force: :cascade |t| t.integer "product_id" t.integer "order_id" t.decimal "unit_price", precision: 12, scale: 3 t.integer "quantity" t.decimal "total_price", precision: 12, scale: 3 t.datetime "created_at", null: false t.datetime "updated_at", null: false t.boolean "has_ordered" end create_table "orders", force: :cascade |t| t.decimal "subtotal", precision: 12, scale: 3 t.decimal "tax", precision: 12, scale: 3 t.decimal "shipping", precision: 12, scale: 3 t.decimal "total", precision: 12, scale: 3 t.integer "order_status_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.integer "user_id" t.boolean "ordered" t.date "first_item_added_at" t.date "first_order_added_at" end
one common way of approaching problem having background process periodically checking database , doing maintenance work necessary (cleaning, calculating intermediate results, etc.).
one simplistic solution checks orders @ least 3 order items , deletes items older 30 days below.
with rails put following under config/initializers/order_cleaner.rb
, gets loaded every time start rails application.
thread.new while true # orders @ least 3 order_items orders = orders.joins(:order_items).group('orders.id').having('count(order_id) >= 3') orders.each |o| # delete associated order_item if it's older 30 days o.order_items.each {|oi| oi.destroy! if oi.updated_at < 30.days.ago } end sleep 1.minute end end
couple notes:
- if orders table gets bigger, practical in database without creating activerecord model instances , separate queries every orderitem
- for more complicated scheduling , job retrying using sidekiq or rufus scheduler worth considering
- more sophisticated solution require cleanup thread, logging , taking care multiple instances don't started (e.g. when you're using unicorn load balance app)
Comments
Post a Comment