仅允许针对特定参数进行一次更新?

时间:2018-11-29 00:53:37

标签: ruby-on-rails ruby stripe-payments

如何设置参数,使其无法再次更新或编辑?

问题:我有一个参数:video,一旦填充,它将向客户收费。我想这样做,以便一旦填充,就无法再次更新或编辑。

我已在视图方面采取了预防措施,一旦上传了视频,则编辑/更新表单将被隐藏并且无法再次创建,但是我注意到,如果由于某种原因更新失败,则可以返回并可以再次填写更新表单(即使视频已上传),从而再次向客户收费两次。

工作方式: 客户创建一个订单,创建一个数据条ID,一旦卖方履行了该订单(通过上传文件或视频),就会收取费用。

  def charge_update
    respond_to do |format|
      @amount = (@order.order_price).to_i * 100
      @amount_seller = (@order.order_price).to_i * 75
      if @order.update(order_charge)
        begin
                      charge = Stripe::Charge.create({
                        :amount      => (@order.order_price).to_i * 100,
                        :description => 'Rails Stripe customer',
                        :currency    => 'usd',
                        :customer => @order.stripe_customer_token,
                        :destination => {
                          :amount => @amount_seller ,
                          :account => (@order.seller.stripe_token),
                        }
                      })
                    rescue Stripe::CardError => e
                      charge_error = e.message
                    end
          @order.update_column(:order_status, 2)
          format.html { redirect_to ([@user, @order]), notice: 'Order was successfully uploaded.' }
          format.json { render :show, status: :ok, location: @order }
        elsif
          if charge_error
            flash[:error] = charge_error
            redirect_to user_order_path([@user, @order])
          else
          format.html { render :edit }
          format.json { render json: @order.errors, status: :unprocessable_entity }
        end
      end
    end
  end
private

def order_charge
      params.require(:order).permit(:video, :order_status)
    end

如果有更好的方法可以验证客户的费用,请随时告诉我。我最大的担心是,由于卖方混乱,恶意等原因,客户被多次收取费用。我想保证仅向客户收取一次费用。我能想到的唯一方法是只允许对视频列进行一次更新。

要么,要么为每个视频表ID唯一的order_id的视频创建单独的表。

更新

我最终完成了以下工作……如果有任何更好的想法,我愿意提出建议!

def charge_update
    respond_to do |format|
    if @order.video.present?
      format.html { redirect_to ([@user, @order]), notice: 'Order already completed!.' }
      format.json { render :show, status: :ok, location: @order }
    else
        @amount = (@order.order_price).to_i * 100
        @amount_seller = (@order.order_price).to_i * 75
        if @order.update(order_charge)
          begin
...
...
...
end

4 个答案:

答案 0 :(得分:0)

更好的方法是制作一个具有这些值的表

order_id 
video_id 
user_id 
charged (Boolean Value )

一旦客户下了订单并收取了费用,您就可以填写这些值并将费用值设为true。

您可以先检查他是否已订购该视频,然后再重新付款。

这是您可以为此模型制作的示例

  class CustomerOrder < ActiveRecord::Base
  belongs_to :customer
  belongs_to :order
  belongs_to :video      
  end 

在客户下新订单之前,您可以检查是否存在任何关系

   @customerorder =CustomerOrder.where(video_id: @video.id , user_id: @user.id , charged :true )

答案 1 :(得分:0)

我将使用ActiveModel::Dirty实现一个回调,以在changing列值从空或无变为任何 not 之后的任何更改上发起回滚。

class Amount < ActiveRecord::Base
  include ActiveModel::Dirty

  before_save :check_video

  attr_accessor :video # or whatever your video attribute is

  private

  def check_video
    false if video_changed? && !video_was.nil? # or empty or whatever
    true
  end
end

答案 2 :(得分:0)

我将确保在模型层中,一旦成功创建记录,便无法再对其进行更新。

一种简单的方法可能是重写Rails在内部检查只读记录的readonly?方法:

# in your model
def readonly?
  super || video.present? && persisted?
end

在只读实例上调用save会引发ActiveRecord::ReadOnlyRecord异常。

使用此方法,您可以在控制器中写入if @order.readonly?并查看@order是否仍可更新。

答案 3 :(得分:0)

我最终创建了一个仅用于上传视频文件的控制器。

通过这种方式,我可以在创建过程中使用费用代码创建上传文件,然后无需单独进行更新就可以进行更新...

到目前为止,这是控制器的要旨:

def create

    @video_order = VideoOrder.new(video_order_params)
    @order = Order.find(params[:order_id])

    @video_order.order_id = @order.id

    respond_to do |format|
      if @order.video_order.present?
          format.html { redirect_to @order, notice: 'Already complete dog!.' }
          format.json { render :show, status: :created, location: @video_order }
        else

      if @video_order.valid?
        begin
          charge = Stripe::Charge.create({
            :amount      => (@order.order_price).to_i * 100,
            :description => 'Rails Stripe customer',
            :currency    => 'usd',
            :customer => @order.stripe_customer_token,
            :destination => {
              :amount => @amount_seller ,
              :account => (@order.seller.stripe_token),
            }
          })
        rescue Stripe::CardError => e
          charge_error = e.message
        end
        if charge_error
          flash[:error] = charge_error
          redirect_to '/'
        else

          if @video_order.save
            @order.update_column(:order_status, 2)
            format.html { redirect_to @order, notice: 'Video order was successfully created.' }
            format.json { render :show, status: :created, location: @video_order }
          else
            format.html { render :new }
            format.json { render json: @video_order.errors, status: :unprocessable_entity }
          end
        end
      end
    end
  end
end

  # PATCH/PUT /video_orders/1
  # PATCH/PUT /video_orders/1.json
  def update
    respond_to do |format|
      if @video_order.update(video_order_params)
        format.html { redirect_to user_order_path([@user, @order]), notice: 'Video order was successfully updated.' }
        format.json { render :show, status: :ok, location: @video_order }
      else
        format.html { render :edit }
        format.json { render json: @video_order.errors, status: :unprocessable_entity }
      end
    end
  end

为了防止万一,我在create方法中也采取了预防措施。