hi i am trying to get my braintree account to display errors when creating a transaction but it doesn't appear to be working
- flash.each do |key, value|
%div{:class => "alert alert-#{key}"}= value
def update
result = Braintree::Transaction.sale(
:amount => params[:amount_to_add].to_f,
# :order_id => "order id",
:customer_id => customer.customer_cim_id,
:tax_amount => (params[:amount_to_add].to_f / 11).round(2),
:options => {
:submit_for_settlement => true
}
)
if result.success?
logger.info "Added to #{params[:amount_to_add].to_f} to #{customer.first_name} #{customer.last_name} (#{customer.customer_cim_id})"
customer.store_credit.add_credit(params[:amount_to_add].to_f)
redirect_to myaccount_store_credit_path
# , :notice => "Successfully updated store credit."
else
result.errors.each do |error|
puts error.message
customer.errors.add(:base, error.message)
render :show, :notice => error.message
end
end
end
I believe the reason you're probably unable to see the errors is because of the :notice option on your render method, which is redundant because render doesn't seem to be using the :notice option, only redirect_to. You may just add the errors to your to your flash, but note that in your view you have to loop through the errors within the flash to render it.
Another way I would think you do this though is add the payment method to your User model
class User|Customer
...
def process_braintree_payment(amount)
result = Braintree::Transaction.sale(
:amount => amount.to_f,
# :order_id => "order id",
:customer_id => customer_cim_id,
:tax_amount => (amount.to_f / 11).round(2),
:options => {
:submit_for_settlement => true
}
)
add_braintree_errors(result.error) unless result.success?
end
def add_braintree_errors(error_object)
error_object.each do |error|
errors.add(:braintree, error.message)
end
end
end
class XController
def update
#customer.process_braintree_payment(params[:amount_to_add])
if #customer.errors.empty?
logger.info "Added to #{params[:amount_to_add].to_f} to #{#customer.first_name} #{#customer.last_name} (#{#customer.customer_cim_id})"
#customer.store_credit.add_credit(params[:amount_to_add].to_f)
redirect_to myaccount_store_credit_path
# , :notice => "Successfully updated store credit."
else
render :show
end
end
end
In your view, you have access to the #customer variable or better you could store the error object in the ActionController#flash, note however, using the same keys for your flash messages, would overwrite the previous value.
Related
I am having this issue and each time I just remove stripe_id then I don't have the error but I get back to the home page without the payment working... Some freelancer did this part and I can't figure out why it doesn't work on my computer but works fine on a server or the freelancer's computer.. the code won't work on any of my computers.. Anybody knows what's the issue I been trying to figure this one out. On the server the payment works...
This is my controller
class SubscriptionsController < ApplicationController
protect_from_forgery :except => :webhooks
before_action :authenticate_user!, except: [:webhooks]
def new
end
# this is for recursive
def subscription_payment
begin
stripe_id = Plan.find_by_plan_type(params[:plan_type]).stripe_id
# stripe_id = Plan.find(params[:plan_id]).stripe_id
#plan = Stripe::Plan.retrieve(stripe_id)
customer = Stripe::Customer.create(
:description => "Customer for #{params[:stripeEmail]}",
:source => params[:stripeToken],
:email => params[:stripeEmail]
)
stripe_subscription = customer.subscriptions.create(:plan => #plan.id)
#payment = current_user.payments.new(customer_id: customer.id, card_exp_month: customer.sources[:data][0]['exp_month'], card_exp_year: customer.sources[:data][0]['exp_year'], card_id: customer.sources[:data][0].id, customer_subscription_id: stripe_subscription.id, plan_id: #plan.id)
#payment.save!
if params[:plan_type] == "monthly"
current_user.build_user_plan(plan_id: #plan.id, plan_expiry: Date.today+1.months).save
elsif params[:plan_type] == "annual"
current_user.build_user_plan(plan_id: #plan.id, plan_expiry: Date.today+1.years).save
else
current_user.build_user_plan(plan_id: #plan.id).save
end
flash[:notice] = 'You have successfully got the premium.'
redirect_to root_path
rescue Stripe::StripeError => e
flash[:error] = e.message
redirect_to root_path
end
end
# Method responsbile for handling stripe webhooks
# reference https://stripe.com/docs/webhooks
def webhooks
begin
event_json = JSON.parse(request.body.read)
event_object = event_json['data']['object']
#refer event types here https://stripe.com/docs/api#event_types
case event_json['type']
# when 'invoice.payment_succeeded'
# handle_success_invoice event_object
# when 'invoice.payment_failed'
# handle_failure_invoice event_object
# when 'charge.failed'
# handle_failure_charge event_object
when 'customer.subscription.deleted'
when 'customer.subscription.updated'
end
rescue Exception => ex
render :json => {:status => 422, :error => "Webhook call failed"}
return
end
render :json => {:status => 200}
end
end
This is my the sign in button where the amount is charged.
<% if user_signed_in? %>
<%= form_tag subscription_payment_path, method: :post do %>
<%= hidden_field_tag :plan_type, "monthly" %>
<script class="stripe-button"
data-amount="1000"
data-currency="CAD"
data-email="<%= current_user.email %>"
data-key="<%= Rails.configuration.stripe[:publishable_key] %>"
src="https://checkout.stripe.com/checkout.js">
</script>
<% end %>
<% else %>
<a href="/users/sign_in" class="btn btn-neutral btn-round">
Subscribe
</a>
<% end %>
If you're seeing undefined method 'stripe_id' for nil:NilClass, then that means Plan.find_by_plan_type(params[:plan_type]) is likely returning nil. And you can't get the stripe_id of nil.
Are you sure that you have database records on your local machine, in particular Plan records with plan_type?
If your want to handle the scenario where a Plan is not found, given the plan_type, then you could try:
plan = Plan.find_by_plan_type(params[:plan_type])
raise SomeSortOfError if plan.nil? # make sure to rescue accordingly
stripe_id = plan.stripe_id
I'm building a small proof of concept with Stripe and Ruby on Rails 3.2. So far I've watched the Railscast on how to implement Stripe in a RoR app and it's working really well.
I've built my app by following RailsCast #288 Billing with Stripe. Now my users can add and edit their credit cards and even register to classes and have their credit card billed upon completion.
Now I've been testing with Stripe's numerous test credit cards and I want to catch as many exceptions when raised. I'm using Stripe's example errors in my Registration model as show here:
class Registration < ActiveRecord::Base
belongs_to :user
belongs_to :session
attr_accessible :session_id, :user_id, :session, :user, :stripe_payment_id
validates :user_id, :uniqueness => {:scope => :session_id}
def save_with_payment(user, stripe_card_token)
if valid?
if user.stripe_customer_id.present?
charge = Stripe::Charge.create(
:customer => user.stripe_customer_id,
:amount => self.session.price.to_i * 100,
:description => "Registration for #{self.session.name} (Id:#{self.session.id})",
:currency => 'cad'
)
else
customer = Stripe::Customer.create(
:email => user.email,
:card => stripe_card_token,
:description => user.name
)
charge = Stripe::Charge.create(
:customer => customer.id,
:amount => self.session.price.to_i * 100,
:description => "Registration for #{self.session.name} (Id:#{self.session.id})",
:currency => 'cad'
)
user.update_attribute(:stripe_customer_id, customer.id)
end
self.stripe_payment_id = charge.id
save!
end
rescue Stripe::CardError => e
body = e.json_body
err = body[:error]
logger.debug "Status is: #{e.http_status}"
logger.debug "Type is: #{err[:type]}"
logger.debug "Code is: #{err[:code]}"
logger.debug "Param is: #{err[:param]}"
logger.debug "Message is: #{err[:message]}"
rescue Stripe::InvalidRequestError => e
# Invalid parameters were supplied to Stripe's API
rescue Stripe::AuthenticationError => e
# Authentication with Stripe's API failed
# (maybe you changed API keys recently)
rescue Stripe::APIConnectionError => e
# Network communication with Stripe failed
rescue Stripe::StripeError => e
# Display a very generic error to the user, and maybe send
# yourself an email
rescue => e
# Something else happened, completely unrelated to Stripe
end
end
I'm merely rescuing from errors right now and not really taking action after one being raised and ultimately I would like to stop the current class registration from happening and redirect a user with a flash error.
I've read about rescure_from but I'm not sure what is the best way to handle of all the possible Stripe errors. I know can't redirect from the model, how would you experts handle this?
Here's my Registration controller:
class Classroom::RegistrationsController < ApplicationController
before_filter :authenticate_user!
def new
if params[:session_id]
#session = Session.find(params[:session_id])
#registration = Registration.new(user: current_user, session: #session)
else
flash[:error] = "Course session is required"
end
rescue ActiveRecord::RecordNotFound
render file: 'public/404', status: :not_found
end
def create
if params[:session_id]
#session = Session.find(params[:session_id])
#registration = Registration.new(user: current_user, session: #session)
if #registration.save_with_payment(current_user, params[:stripe_card_token])
flash[:notice] = "Course registration saved with success."
logger.debug "Course registration saved with success."
mixpanel.track 'Registered to a session', { :distinct_id => current_user.id,
:id => #session.id,
'Name' => #session.name,
'Description' => #session.description,
'Course' => #session.course.name
}
mixpanel.increment current_user.id, { :'Sessions Registered' => 1}
mixpanel.track_charge(current_user.id, #session.price.to_i)
else
flash[:error] = "There was a problem saving the registration."
logger.debug "There was a problem saving the registration."
end
redirect_to root_path
else
flash[:error] = "Session required."
redirect_to root_path
end
end
end
Thanks for taking the time to respond, much appreciated!
Francis
Have you thought of putting the actually Stripe call in a custom validator?
http://apidock.com/rails/ActiveModel/Validations/ClassMethods/validate
That way you could add errors to the object with something like the following
The logic behind this is you only want to save successful transactions as 'transaction' anyway so why not just put the Stripe charge in the validator.
validate :card_validation
def card_validation
begin
charge = Stripe::Charge.create(
:customer => user.stripe_customer_id,
:amount => self.session.price.to_i * 100,
:description => "Registration for #{self.session.name} (Id:#{self.session.id})",
:currency => 'cad'
)
etc etc
rescue => e
errors.add(:credit_card, e.message)
#Then you might have a model to log the transaction error.
Error.create(charge, customer)
end
end
This way you can handle the errors like any other errors you would get from a entry not saving, instead of giving a blank error message, or having to handle every last error from Stripe.
class Classroom::RegistrationsController < ApplicationController
before_filter :authenticate_user!
def create
if params[:session_id]
#session = Session.find(params[:session_id])
params[:registration][:user] = current_user
params[:registration][:session] = #session
params[:registration][:stripe_card_token] = params[:stripe_card_token]
#registration = Registration.new(params[:registration])
respond_with(#registration) do |format|
if #registration.save
format.html {redirect_to root_path, :notice => "SOMETHING HERE TO TELL THEM SUC"}
else
format.html {render}
end
end
else
respond_with do |format|
format.html {redirect_to root_path, :error => "SOMETHING HERE TO TELL THEM GET SESSION"}
end
end
end
end
I have a Item model that has embedded documents. Currently, the following comments_controller code will add a comment to the item successfully. However, if pushing the comment document onto the comments array on item fails, I will not know this.
#this does work, but i do not know if the push fails
def create
comment = Comment.new(:text => params[:text])
#item.comments << comment
render :text => comment
end
I would like to have something like this, but #item.comments << comment does not return true or false:
#this does not work
def create
comment = Comment.new(:text => params[:text])
if #item.comments << comment
render :text => comment
else
render :text => 'oh no'
end
end
Nor does it throw an exception when the document push fails:
#this does not work
def create
begin
comment = Comment.new(:text => params[:text])
#item.comments << comment
render :text => comment
rescue Exception => e
render :text => 'oh no'
end
end
Thanks!
You have to set the item for the comment, then persist it. comment.save will return true if the save goes well and return false otherwise. You can handle both scenarios as you see fit.
def create
comment = Comment.new(:text => params[:text])
comment.item = #item
if comment.save
render :text => "yay"
else
render :text => "oh no"
end
end
I am using this controller to respond to an ajax request, what I am trying to accomplish, is if the user is not logged in, thus the user_id = nil, to not attempt to save the vote and return the "err" partial...But ajax returns a 500 error, can't figure it out. The create method with user_id does work correctly
def create
unless params[:user_id].nil?
#vote = Vote.new(:song_id => params[:song_id], :user_id => params[:user_id])
#vote.save
#song = Song.where(:id => params[:song_id])
render :partial => "votes/ret", :locals => { :song => #song }, :layout => false, :status => :created
else
render :partial => "votes/err", :layout => false
end
end
Do you have an association in your model?
Than you could solve this much easier.
Best would be if you can tell about association and post the console output of your error.
And you could change
unless params[:user_id].nil?
to:
if params[:user_id]
which is doing the same and easier to read.
Bests
A user can only edit its own post, so I use the following to check if a user can enter the edit form:
def edit
#post = Load.find(:first, :conditions => { :user_id => session[:user_id], :id => params[:id]})
rescue ActiveRecord::RecordNotFound
flash[:notice] = "Wrong post it"
redirect_to :action => 'index'
end
But it is not working, any ideas what I am doing wrong?
If you want to use the rescue statement you need to use find() in a way it raises exceptions, that is, passing the id you want to find.
def edit
#post = Load.scoped_by_user_id(session[:user_id]).find(params[:id])
rescue ActiveRecord::RecordNotFound
flash[:notice] = "Wrong post it"
redirect_to :action => 'index'
end
You can also use ActionController's rescue_from method. To do it for the whole application at once!
class ApplicationController < ActionController::Base
rescue_from ActiveRecord::RecordNotFound, :with => :record_not_found
def record_not_found
render 'record_not_found' # Assuming you have a template named 'record_not_found'
end
end
Turns out you were using rescue and find(:first) incorrectly.
find :first returns nil if no record matches the conditions. It doesn't raise ActiveRecord::RecordNotFound
try
def edit
#post = Load.find(:first, :conditions => { :user_id => session[:user_id], :id => params[:id]})
if #post.nil?
flash[:notice] = "Wrong post it"
redirect_to :action => 'index'
end
end