简体   繁体   中英

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

I am working on a marketplace in rails that allows buyers to make an offer to the seller as a bid for a listing. The seller can cancel or accept the bid but only has a 24 hr window to do this or the bid expires and the transaction is cancelled. A user can be both a buyer or a seller.

I have an Order model that represents each transaction.

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

On my reservation controller, Class OrdersController < Application Controller 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

I want to differentiate between a buyer cancel and seller cancel because if a seller cancels a bid for a listing the buyer pays no bidding fee but if the buyer cancels the order he made he is charged a bidding fee. How can the transactions for bids be implemented. The hardest part is figuring out creating a timer in rails that will show the seller how much time is left eg 4 hrs 12 min before the bid expires and cancelling the bid after 24 hrs if there's no response especially keeping in mind different client side time zones that may be hours apart from the created_at time of the order. I also need to show order status as pending, canceled or accepted which rules out boolean functionality because that creates three possible statuses. Any kind of help in any of these problems would be greatly appreciated.

You might have noticed that in bids table (I am assuming the table name) there is a field called created_at . You can use this as the start-time indicator.

In bids page where you show all the bids to seller . Either you can

  • only show the valid bids ( bids.where('bids.created_at > ?', 24.hours.ago) )
  • Or, show all the bids but disable the bids created before 24 Hours

Better way would be keeping track of the status of the bid with status attribute. To invalidate a bid after 24Hours you can use background processors like sidekiq , resque .

For example: With Sidekiq

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

Update

Do you know how to check the time on the client side based on the timezone of the created_at timestamp on the database if you take into account some users may make an offer before the created_at time if they live 6hrs behind in Alaska?

Well, ActiveRecord stores all date-time in UTC time so that developers can converted it to any timezone you like.

You need to set TimeXone according to user's timezone. You can store timezone offset in browser cookie and get the offset to calculate the timezone in Server side.

$(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
  }
})

in application_controller you can

  # 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

Note : Time.zone is thread safe.

Now you need to use DateTime.current in place of DateTime.now

Does it provide functionality to create a worker that checks the status attribute a little more frequently like every ten minutes.If a bid is cancelled Immediately I don't want to have to wait 24hrs before informing a buyer the bid is cancelled

Well to execute tasks in specific point of time you can create cronjobs using Whenever gem

You do not really need a timer. You just need the time until the bid is valid. I guess you will have some kind of Bit model. When a bit is created by a buyer store when the bid expires in a expires_at column:

class Bid < ActiveRecord::Base
  before_create :set_expired_at

  private
  def set_expired_at
    self.expired_at = Time.current + 24.hour
  end
end

This allows you to add an expired? method to the same class which you could use in the view to decide if you want to still list an offer:

def expired?
  expired_at < Time.current
end

Or you could add a scope to only load unexpired bits:

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

If an offer is pending or was excepted could be implemented as a simple accepted boolean in the database. Which lead to the following status method:

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

Since all this methods a depending on the current time, there is no need for an external timer, a cron job or a background job. The model it self is always able to return the current state.

You could use delayed_job , sidekiq or resque or similar tools to schedule your function to be called as soon as the bid is created. And when 24 hour is up, when the function get's called you can check there if it was accepted or not.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM