如何使数据库中保存的数据在一段时间后过期?

时间:2016-06-29 11:22:11

标签: ruby-on-rails database model-view-controller database-design model

我在铁轨上建一家商店。商店有订单,order_items,用户..

现在,当客户将order_item添加到购物车时,将自动创建具有唯一ID的订单,并且order_items将保存在order_items模型下。还有验证说一个订单只允许3个order_items。

如果可能,我想删除30天后保存到模型中的那些order_items。保存3 order_items后,30天计数器应该开始。

我怎样才能做到这一点?

由于

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 are allowed within an order for 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 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_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 do |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 do |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 do |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

1 个答案:

答案 0 :(得分:1)

解决此问题的一种常见方法是让后台进程定期检查数据库并进行必要的维护工作(清理,计算某些中间结果等)。

一个简单的解决方案,用于检查包含至少3个订单商品的订单,并删除超过30天的商品。

使用rails,您可以将以下内容放在config/initializers/order_cleaner.rb下,然后每次启动Rails应用程序时都会加载它。

Thread.new do
  while true
    # Get all orders with at least 3 order_items
    orders = Orders.joins(:order_items).group('orders.id').having('count(order_id) >= 3')
    orders.each do |o|
      # Delete associated order_item if it's older than 30 days
      o.order_items.each {|oi| oi.destroy! if oi.updated_at < 30.days.ago }
    end
    sleep 1.minute
  end
end

情侣笔记:

  1. 如果订单表变得更大,那么在数据库中执行所有内容而不创建ActiveRecord模型实例并为每个 OrderItem
  2. 创建单独的查询是切实可行的
  3. 使用SidekiqRufus Scheduler进行更复杂的计划和作业重试值得考虑
  4. 更复杂的解决方案需要清理线程,一些日志记录并注意多个实例无法启动(例如,当您使用Unicorn来平衡应用程序时)