Rails: Stripe appears to work but no charge is created - ruby-on-rails

I have a rails app where Stripe is set up similar to this documentation. When I hit the "Pay With Card" button and enter the test card information it says it's successful, then gives me an error message saying:
No route matches [POST] "/charges/new"
Even though my routes are like this:
resources :charges
get 'charges/shipping'
get 'charges/address'
post 'charges/update_order'
My charges_controller reads like this:
class ChargesController < ApplicationController
...
def new
#order = current_order
end
def create
# Amount in cents
#amount = current_order.total * 100
#user = current_user
#order = current_order
if #user.stripe_customer_id
customer = #user.stripe_customer_id
else
customer = Stripe::Customer.create(
:email => params[:stripeEmail],
:source => params[:stripeToken]
)
#user.update_attributes(stripe_customer_id: customer.id)
end
#order.update_attributes(order_status_id: 2)
#order.update_attributes(date_placed: DateTime.now)
# OrderMailer.order_placed(#order.user, #order).deliver_now
session[:order_id] = nil
charge = Stripe::Charge.create(
:customer => #user.stripe_customer_id,
:amount => #amount.to_i,
:description => 'Rails Stripe customer',
:currency => 'usd'
)
rescue Stripe::CardError => e
flash[:error] = e.message
redirect_to new_charge_path
end
private
def order_params
params.permit(:subtotal, :tax, :shipping, :total, :order_status_id, :user_id, :date_placed, :shipping_choice)
end
end
If I manually insert a post "charges/new" into the routes.rb it says it's successful, but it redirects to the same page (indicating a Stripe::CardError) and no charge registers in the stripe dashboard.
Can anyone see where I'm going wrong?

It looks like you're not permitting the 'stripeToken' parameter in your order_params. Because of camel-case that might be a little fiddly, but make sure you're allowing that param with something like:
params.permit( :"stripeToken" …
Without this, that parameter is null, and would give you a Stripe failure.

Without seeing your client side code, I can't be sure - but it sounds like your client side code is trying to POST to /charges/new - which doesn't exist - so it's failing. I'd suggest you update your client side code to POST to the route you want to have handle that, and then continue debugging from there.

The problem is this part here in your controller:
rescue Stripe::CardError => e
flash[:error] = e.message
redirect_to new_charge_path
You should remove redirect_to new_charge_path, and simply just let Stripe render the error message. No need to redirect upon error. Stripe takes care of the error-handling for you (which is one of the things making Stripe great).
Currently, your redirect_to is being treated as the path after each successful purchase. Not just on errors.
Update
Upon further looking at your code. You don´t seem to actually have a redirect_to after each successful purchase. So regardless, you should remove the redirect_to new_charge_path because it´s currently arbitrary to => e. It might look like it has something to do with the Error handiling, cause it's below that block, but in fact it doesn't. You should instead add redirect_to successful_path or render :success (for instance) right above the rescue Stripe::CardError =>. And then let Stripe handle (or rescue) failed attempts to make a purchase, as explained before.

Try to restart your server to reload the routes. Run rake routes | grep charges to verify that you see POST /charges/new.
Wait, I know why. You are supposed to GET /charges/new and POST to /charges. Show us your view code, specifically the form submission URL address.
See http://guides.rubyonrails.org/routing.html#crud-verbs-and-actions

In the end I had to change the code on the form to charge_path instead of new_charge_path so it would hit the create action. Even though this was different from the Stripe documentation it ended up working.

Related

Invalid Userid or postid etc. Error on Editing the URL in Ruby on Rails

So i am trying to set a validation in post model if someone tries to edit in the url and enter another post number like:
from this
http://localhost:3000/posts/1
to this
http://localhost:3000/posts/112318278
and when user enter it should show some error msg or redirect to some other page or stuff...
how to do that ?
First, you can't. Take StackOverflow for example
https://stackoverflow.com/questions/73189649 if I want to change this to a different id, I can and it will work https://stackoverflow.com/questions/73189659
Second, your backend will attempt at finding the post with the given id, from your controller. One thing you could do is put a rescue clause in the finder.
(this is one of many ways to do it, but it's the simplest)
def find_post
#post = Post.find(params[:id]) # => This will raise an error if the post does not exist
rescue ActiveRecord::RecordNotFound => e # => This will rescue that error, and send the user to a different page, and not the Rails' 404 page
redirect_to(some_path, notice: 'This post does not exist')
end

Unable to verify stripe payment correctly in controller

so I just noticed I had a small problem. I'm using Stripe as my payment processor, and what happened was quite simple. I had a bug in my code which didn't allow me to save the customer_id_token and change a boolean called subscription active.
However the payment still went through (confirmed in stripe logs). Thus it's obvious I don't have proper validations in place as this should never happen. Here's what my code looks like now:
def create
customer = Stripe::Customer.create(
:email => current_user.email,
:plan => params[:plan_id],
:card => params[:stripeToken]
)
current_user.update_attributes!(
:stripe_customer_token => customer.id,
:subscription_active => true,
:plan_id => params[:plan_id]
)
redirect_to root_url, notice: 'Successfully subscribed'
rescue Stripe::CardError => e
flash[:error] = e.message
redirect_to charges_path
end
I can see that they are obviously not really connected with one another, and my question is how can I turn this into something that if the customer_token is not saved it won't go through with the payment either?
Okay,
I'm going to take a shot at this, problem is I do not know how Stripe works, so I cannot guarantee this to work.
I just want to demonstrate the usage of transactions:
def create
ActiveRecord::Base.transaction do
customer = Stripe::Customer.create(
email: current_user.email,
plan: params[:plan_id],
card: params[:stripeToken]
)
current_user.update_attributes!(
stripe_customer_token: customer.id,
subscription_active: true,
plan_id: params[:plan_id]
)
end
redirect_to root_url, notice: 'Successfully subscribed'
rescue Stripe::CardError => e
flash[:error] = e.message
redirect_to charges_path
end
What I would definitely add to your current_user model, is a validation to check that the token cannot be null:
class User < ActiveRecord::Base
validates :stripe_customer_token, presence: true
end
That way the update fails when the token is not provided, rolling back the transaction. Although with this it should also work if the first call fails.
However this will only work if this Stripe::Customer supports transactions. I do not know or gurantee this to be the solution.
If the Customer call still goes through and does not validate whether the payment is valid, then there's not much you can do.

NoMethodError in ConfirmationController

I have been trying to solve the following problem for a couple of days. Forgive me if this is a common problem as I am new to rails and probably couldn't query the right question/keyword in stackoverflow or google.
I am building a system where a user will get an invite via email, click on a unique link, be taken to a page where he/she can accept or decline the invitation. I am getting stuck at the part where the user accepts or declines the invitation.
I've built it around two controllers: an invitations controller and a confirmations controller.The invitations controller creates a record containing a name, an email, and a uniquely generated token. The controller then emails a link with the token to the defined email. The link points to the confirmations controller and passes the unique token from the invitation. However, when clicking on the link and accepting the invitation, I get the following error:
NoMethodError in ConfirmationController#confirm
undefined method `update_attribute' for nil:NilClass
Here is some of the code for solving this issue:
Confirmation_controller.rb
class ConfirmationController < ApplicationController
def new
#confirmation = Invitation.find_by_invite_token(params[:invite_token])
end
def confirm
if #confirmation.update_attribute(:accepted, true)
flash[:success] = "Invitation confirmed!"
redirect_to 'static_pages/home'
else
flash[:notice] = "Failed :("
redirect_to 'static_pages/home'
end
end
end
routes.rb
match '/confirmation/:invite_token', to: 'confirmation#new'
match '/confirmation/:invite_token/confirm', to: 'confirmation#confirm'
app/views/confirmation/new.html.erb
Click here to accept:
<%= link_to "Confirm", :controller => "confirmation", :action => "confirm" %>
You need to get your Invitation in the confirm method too.
If you want rails to raise an exception if no invitation was found
def confirm
#confirmation = Invitation.find_by_invite_token!(params[:invite_token])
#confirmation.update_...
end
No exception will be raise. You may want to check manually with a condition in the following case.
def confirm
#confirmation = Invitation.find_by_invite_token(params[:invite_token])
if #confirmation
#confirmation.update_...
else
# do something
end
end
You should find confirmation record before calling update_attribute on it, like you did it in new action:
#confirmation = Invitation.find_by_invite_token(params[:invite_token])
Or, to throw exception when the record is not found and to render 404 page to the user:
#ocnfirmation = Invitation.find_by_invite_token!(params[:invite_token])
The problem is that you never told the program what #confirmation is. What you should do is find it first then run the update. Note this is different from the different answers, just thought I would throw in some variety.
def confirm
# You're missing this line below. Basic search for the confirmation.
# Note too that you will have to pass in the parameter `invite_token` for it to work
# I'm also assuming invite_token is unique among each invitation
confirmation = Invitation.where(invite_token: params[:invite_token])
# Notice that I'm first checking to see if the confirmation record exists, then doing an update
if confirmation and confirmation.update_attribute(:accepted, true)
flash[:success] = "Invitation confirmed!"
redirect_to 'static_pages/home'
else
flash[:notice] = "Failed :("
redirect_to 'static_pages/home'
end
end

Implementing a specific action for a model that respond_with(#object)

I have a Subscription model that users can create. Users needs to validate a PIN sent to them to confirm subscription after is created. I'm having a bit of trouble trying to figure it out the best way to implement this.
I implemented a confirms controller with two new and create actions.
def new
#confirm = Subscription.new
end
def create
#keyword = Keyword.joins(:shortcode).where("shortcodes.shortcode = ? and shortcodes.country = ?",params[:subscription][:shortcode],params[:subscription] [:country]).find_or_create_by_keyword(params[:subscription][:keyword])
if #confirm = Subscription.where(:phone => params[:subscription][:phone], :country => params[:subscription][:country], :keyword_id => #keyword.id).last
#confirm.check_subscription_pin(params[:subscription][:pin])
respond_with(#confirm)
elsif #confirm && #confirm.errors.any?
flash[:notice] = #confirm.errors
render :action => :new
else
flash[:notice] = "Subscription not found."
render :action => :new
end
end
This solution doesn't look very convincing since I would like to always respond_with(#confirm) to allow REST POST done via JSON.
There's no params[:subscription] received when you make your curl call. Phone and Pin are nested within subscription, hence the error.
<pre>undefined method `[]' for nil:NilClass</pre>
I don't know how to make a curl call with nested params by the way.

Rails 2.3.5: flash[:notice] disappears after redirect_to call

Here I've got two controller methods:
def invite
if request.post?
begin
email = AccountMailer.create_invite(#user,url)
AccountMailer.deliver(email)
flash[:notice] = "Invitation email sent to #{#user.email}"
rescue
#mail delivery failed
flash[:error] = "Failed to deliver invitation"
end
redirect_to :action => :show, :id => #user.id
end
end
and
def show
#title = "User #{#user.full_name}"
end
The problem is, when I send an invitation, and get redirected to ./show, I see no messages at all. If I change redirect_to to render, the message appears. Still, isn't it intended for flash to work in the immediate subsequent requests?
BTW, I'm using Rails+Passenger setup, could it be so that redirected request goes to another application instance?
The rescue block is setting flash[:error], not flash[:notice]. Is your view actually rendering both?
Googled better and found this discussion:
http://www.mail-archive.com/activescaffold#googlegroups.com/msg04284.html
The solution is there: replace the plugin with
script/plugin install git://github.com/ewildgoose/render_component.git -r rails-2.3 --force
Though I don't use ActiveScaffold, there is some legacy code that depends on render_component plugin. Updating plugin to branch version worked, though I'm planning to get rid of it completely.

Resources