nonegiven72
nonegiven72

Reputation: 427

Check validation before save rails

Using Stripe and want to: 1. check model validation 2. if no errors process card token. 3. If card works then save new record.

Below I have it where it processes card first, then if successful, saves record. Unfortunately that record might fail validation but the card was already charged.

As a hack I have a js validation (that mirrors the model validations) in the view that doesn't allow the form to be submitted until the terms are met.

Tourregistration.rb Controller

    def create
token = params[:tourregistration][:stripeToken]
begin
  charge = Stripe::Charge.create(
  :amount => (params[:tourregistration][:invoice].to_d*100).round,
  :currency => "usd",
  :source => token,
  :description => "Example charge"
  )
rescue Stripe::CardError => e
  # The card has been declined
  redirect_to :back, :notice => "#{e}"
else

@tourregistrations = tourregistration_data.map do |tourregistration_params|
  Tourregistration.new(tourregistration_params)
end

@tourregistrations.each(&:save)

  if @tourregistrations.all?(&:valid?)
    flash[:notice] = 'Sign-up Complete'
    redirect_to root_url
  else
    redirect_to :back, :notice => "Something went wrong. Please fill in all fields."  
  end    
end

end

Tourregistration.rb Model

class Tourregistration < ActiveRecord::Base
belongs_to :patron
belongs_to :tour
has_one :referrer

validates :fname, length: { minimum: 2}
validates :lname, length: { minimum: 2}
validates :email, presence: true
validates :price, presence: true
validates :invoice, presence: true
validates :patron_id, presence: true
validates :tour_id, presence: true
end

Upvotes: 0

Views: 1432

Answers (1)

m_x
m_x

Reputation: 12564

Other than callbacks, you can use a database transaction, for example :

ActiveRecord::Base.transaction do
  results = @tourregistrations.map(&:save) # validate and save the records
  raise ActiveRecord::Rollback if results.any?{|result| result == false } # rollback the transaction if any registration failed to be saved
  payment = charge_card # process the payment
  raise ActiveRecord::Rollback unless payment # rollback if payment failed
end

As a side note, this kind of logic is a textbook example for a service object.

Upvotes: 2

Related Questions