我如何在Rails中实现卖家可以在24小时内取消或接受的出价,或者交易被取消

How can I implement in Rails bid offers that sellers can cancel or accept within 24hrs or transaction is cancelled?

本文关键字:取消 交易 或者 Rails 实现 卖家 24小时      更新时间:2023-09-26

我在rails的一个市场上工作,该市场允许买家向卖家出价购买物品。卖家可以取消或接受出价,但只有24小时的时间窗口,否则出价到期,交易被取消。用户既可以是买方,也可以是卖方。

我有一个订单模型来表示每一笔交易。

Class Order < ActiveRecord::Base
    belongs_to :seller, class_name: "User"
    belongs_to :buyer, class_name: "User"
    belongs_to :listing
end

在我的预订控制器上,类订单控制器<应用程序控制器before_action:authenticate_user!

def create 
    @order = Order.new(order_params)
    @seller = @order.listing.user
    @order.buyer_id = current_user.id
    @order.seller_id = @seller.id
    @bidding_fee = @order.bidding_fee
end

我想区分买家取消和卖家取消,因为如果卖家取消了对物品的出价,买家不支付出价费,但如果买家取消了他所做的订单,他将被收取出价费。如何执行投标交易。最困难的部分是在rails中创建一个计时器,向卖家显示还剩多少时间,例如在出价到期前4小时12分钟,如果没有回应,则在24小时后取消出价,特别是要记住不同的客户端时区,这些时区可能与订单的created_at时间相隔数小时。我还需要将订单状态显示为挂起、取消或接受,这排除了布尔功能,因为这会创建三种可能的状态。在这些问题上提供任何帮助都将不胜感激。

您实际上并不需要计时器。你只需要时间,直到出价有效。我想你会有某种Bit型号。当expires_at列中的出价到期时,买方商店创建比特时:

class Bid < ActiveRecord::Base
  before_create :set_expired_at
  private
  def set_expired_at
    self.expired_at = Time.current + 24.hour
  end
end

这允许您将expired?方法添加到同一类中,您可以在视图中使用该方法来决定是否仍要列出报价:

def expired?
  expired_at < Time.current
end

或者你可以添加一个作用域来只加载未过期的位:

scope :unexpired, -> { where('expired_at < ?', Time.current) }

如果报价挂起或被排除,则可以在数据库中实现为简单的accepted布尔值。这导致了以下status方法:

def status
  if accepted?
    'accepted'
  else
    expired? ? 'expired' : 'pending'
  end
end

由于所有这些方法都取决于当前时间,因此不需要外部计时器、cron作业或后台作业。模型本身总是能够返回当前状态。

您可能已经注意到,在bids表中(我假设表名)有一个名为created_at的字段。您可以将其用作start-time指示器。

bids页面中,您可以显示对seller的所有出价。要么你可以

  • 仅显示有效投标(bids.where('bids.created_at > ?', 24.hours.ago)
  • 或者,显示所有bids,但禁用在24 Hours之前创建的出价

更好的方法是跟踪具有status属性的投标状态。要在24小时后使bid无效,可以使用sidekiqresque等后台处理器。

例如:使用Sidekiq

BidInvalidator.perform_in(24.hours, 'mike', 1)
BidInvalidator.perform_at(24.hours.from_now, 'mike', 1)

更新

你知道如何根据数据库上created_at时间戳的时区帐户某些用户可能会在created_at时间之前提出报价,如果他们住在阿拉斯加6小时后?

ActiveRecord以UTC时间存储所有日期时间,这样开发人员就可以将其转换为您喜欢的任何时区。

您需要根据用户的时区设置TimeXone。您可以将timezone offset存储在浏览器cookie中,并在服务器端获得offset来计算timezone

$(document).ready(function(){
  if(!($.cookie('time_zone'))) {
    current_time = new Date();
    expired_after_days = 365;
    $.cookie('time_zone', current_time.getTimezoneOffset(), { path: '/', expires: expired_after_days } );
    // Here expired_after_days represents the number of days the cookies will store the info
  }
})

application_controller中,您可以

  # setting the time zone with the current time zone offset
  before_filter :set_time_zone
  def set_time_zone
    time_zone_offset = cookies[:time_zone].to_i
    Time.zone = ActiveSupport::TimeZone[-time_zone_offset.minutes]
  end

注意Time.zone是线程安全的。

现在您需要使用DateTime.current来代替DateTime.now

它是否提供了创建一个检查状态属性的频率稍微高一点,比如每十分钟一次。如果投标被立即取消我不想在24小时前等待通知买方投标被取消

要在特定时间点执行任务,可以使用Whenever gem 创建cronjobs

您可以使用delayed_jobsidekiqresque或类似工具来安排在创建出价后立即调用您的函数。当24小时结束时,当函数get被调用时,你可以在那里检查它是否被接受。