Booking Process Issues - Stripe and Rails - ruby-on-rails

OK, I have been trying to find the issue for the past 2 hours.. For some reason my bookings don't come through, not even notifications appear on the page.
When I click BOOK NOW, the page reloads and doesn't give me any errors, so not sure what am I doing wrong.
I'm adding the stripe to the booking path step by step. The BOOK NOW button was working fine on its own before, but now that I aded the card charges to it - it doesn't.
Any help is very welcome! Happy to provide additional information, if needed.
Thank you
Reservations Controller
def create
room = Room.find(params[:room_id])
if current_user.stripe_id.blank?
flash[:alert] = "Please update your payment method."
return redirect_to payment_method_path
#reservation = current_user.reservations.build
#reservation.room = room
#reservation.price = room.price
#reservation.total = room.price * days
if #reservation.Waiting!
if room.Request?
flash[:notice] = "Request sent succesfully"
else
charge(room, #reservation)
end
else
flash[:alert] = "Cannot make a reservation"
end
end
redirect_to room
end
def your_trips
#rooms = current_user.rooms
end
def aprove
charge(#reservation, room, #reservation)
redirect_to your_trips_path
end
def decline
#reservation.Declined!
redirect_to your_trips_path
end
Reservations Controller - private
private
def set_reservation
#reservation = Reservation.find(params[:id])
end
def charge(room, reservation)
if !reservation.user.stripe_id.blank?
customer = Stripe::Customer.retrieve(reservation.user.stripe_id)
charge = Stripe::Charge.create(
:customer => customer.id,
:amount => reservation.price,
:description => room.overview,
:currency => "usd"
)
if charge
reservation.Approved!
flash[:notice] = "Reservation created successfully!"
else
reservation.Declined!
flash[:alert] = "Cannot charge with this payment method!"
end
end
rescue Stripe::CardError => e
reservation.declined!
flash[:alert] = e.message
end

After checking current_user.stripe_id.blank? it looks like you are unintentionally returning all requests.
I would try this:
if current_user.stripe_id.blank?
flash[:alert] = "Please update your payment method."
redirect_to payment_method_path and return
end
If your model code depends on the record being saved before calling Waiting!, keep in mind that #reservation = current_user.reservations.build does not save the record.
The rescue block in your charge method also appears to be out of scope. That could be refactored into a begin-rescue-end block within the first if.
And if you aren't seeing notifications on the page, make sure your layout displays :notice and :alert somewhere.

Related

Ruby - how to multiply variables within a method

I'm using a method to try and multiply two variables as follows -
def total_amount
self.quantity.to_i * self.event.price.to_i
end
I'm building an events app using Ruby on Rails and the aim of the method is to allow one user to book multiple spaces for a paid event.
The method simply isn't working as when I click through to make a payment the amount simply shows as 0(zero). The method is in my booking model, in my bookings controller I have the following code -
class BookingsController < ApplicationController
before_action :authenticate_user!
def new
#event = Event.find(params[:event_id])
#booking = #event.bookings.new(quantity: params[:quantity])
#booking.user = current_user
end
def create
#event = Event.find(params[:event_id])
#booking = #event.bookings.new(booking_params)
#booking.user = current_user
Booking.transaction do
#event.reload
if #event.bookings.count > #event.number_of_spaces
flash[:warning] = "Sorry, this event is fully booked."
raise ActiveRecord::Rollback, "event is fully booked"
end
end
if #booking.save
# CHARGE THE USER WHO'S BOOKED
# #{} == puts a variable into a string
Stripe::Charge.create(
amount: #event.price_pennies,
currency: "gbp",
card: #booking.stripe_token,
description: "Booking number #{#booking.id}")
flash[:success] = "Your place on our event has been booked"
redirect_to event_path(#event)
else
flash[:error] = "Payment unsuccessful"
render "new"
end
if #event.is_free?
#booking.save!
flash[:success] = "Your place on our event has been booked"
redirect_to event_path(#event)
end
end
private
def booking_params
params.require(:booking).permit(:stripe_token, :quantity)
end
end
I have an input space on my events.show form which allows the user to input the number of spaces they require. The booking form has the following line of code which should reflect the total amount required -
<p>Total Amount<%= #booking.total_amount %></p>
I added .to_i to both variables as without this I received a NilClass error. How can I amend this so the method creates the correct output?
You can use regex to strip your currency symbol
def total_amount
quantity.to_i * strip_currency(event.price)
end
private
def strip_currency(amount = '')
amount.to_s.gsub(/[^\d\.]/, '').to_f
end
If you are calling booking.new that means you are creating an instance of the class where as self. means you are using a class variable.
Remove the self.

Rails Active Record validates_precense_of not flashing error message

I have a text box in a rails application that I want to validate the pretense of an input before saving to the db. So, I tried placing a validates_precense_of callback in the correct model (as shown below).
class Suggestion < ActiveRecord::Base
attr_accessible :details, :metadata, :suggestible, :user
belongs_to :suggestable, polymorphic: true
belongs_to :user
serialize :metadata, JSON
validates_presence_of :details
end
Instead of the request failing and flashing an error message, the request is successful, and no suggestion record is ever saved in the suggestions table.
I've debugged and confirmed (see controller below) #suggestion.details.blank? and .empty return true is the text box is empty.
Here's the controller action:
def select_patients
#rx_search_request = RxSearchRequest.find(params[:id])
#groups = []
params['selected_patient_group'].each do |id, selected|
#groups << id if selected == "true"
end
unless #groups.blank?
#rx_search_request.select_multiple_patient_group_ids(#groups)
unless #rx_search_request.approval_status_reason_patients_and_approval? ||
#rx_search_request.approval_status_reason_requires_approval?
#rx_search_request.needs_consolidation!
# #rx_search_request.approve! approved_by: current_user
#redirect_url = rx_search_request_path(#rx_search_request)
# #message = "Request has been created."
else
#message = "Request has been forwarded to your admin for approval."
end
end
if params.keys.include? "suggestion"
#we are submitting a suggestion
group_ids = params[:selected_patient_group].collect{|k,v| k if v == 'true'}.compact
metadata = {
group_ids:group_ids,
patient_ids:ManualConsolidationPatientGroup.find(group_ids).collect{|g| g.manual_consolidation_patients}.flatten.collect{|_p| _p.id}
}
#suggestion = #rx_search_request.suggestions.new({
details:params[:suggestion_box],
metadata: metadata
})
#suggestion.user = current_user
#suggestion.save
# #message = "Your suggestion has been submitted."
# debugger
# flash[:alert] = 'Your suggestion cannot be blank' if #suggestion.details.empty?
flash[:alert] = 'Your suggestion has been submitted.'
end
respond_to do |format|
format.js
end
end
Changed the controller to this
unless #suggestion.details.blank?
flash[:alert] = 'Your suggestion has been submitted.'
else
flash[:alert] = 'Your suggestion cannot be blank'
end
#debugger
#suggestion.save!
also tried this
if #suggestion.save!
flash[:alert] = 'Your suggestion has been submitted.'
else
flash[:alert] = 'Your suggestion cannot be blank'
end
SOLUTION
Added bang operator ! to make correct save
You need either to check for the result of save call, or to make it save! instead for the request to fail:
if #suggestion.save
flash[:alert] = 'Your suggestion has been submitted.'
else
flash[:alert] = 'Your suggestion cannot be blank'
end
If you want the validation error to be shown after AJAX request, you need to add something like this to your <controller_name>.js.erb file:
<% flash.each do |type, message| %>
$("#your_element_id").html("<%= type.to_s.humanize %>: <%= message.html_safe %>")
<% end %>
...where you should change #your_element_id to actual HTML ID of element on your page in which you render flash messages.

Updating column from being NULL after action is called

Stripe is setup on my app and users can cancel or upgrade their subscription. It communicates perfectly to Stripe. I need help figuring out how I can make the changes communicate with my database.
If a user cancels their subscription it should be marked in the Subscriptions table under a cancelled column. With this in place the user will be restricted access to website if it shows in the database that their subscription was cancelled.
I am not sure how to add this to the cancel subscription action I have setup.
Help with this would be greatly appreciated!
Subscriptions controller:
def new
plan = Plan.find(params[:plan_id])
#subscription = plan.subscriptions.build
if params[:PayerID]
#subscription.paypal_customer_token = params[:PayerID]
#subscription.paypal_payment_token = params[:token]
#subscription.email = #subscription.paypal.checkout_details.email
end
end
def create
#subscription = Subscription.new(params[:subscription])
if #subscription.save_with_payment
redirect_to #subscription, :notice => "Thank you for subscribing!"
else
render :new
end
end
def show
#subscription = Subscription.find(params[:id])
end
def updatesubscription
#user = current_user
#customer = Stripe::Customer.retrieve(#user.subscription.stripe_customer_token)
#customer.update_subscription(:plan => "1", :prorate => true)
current_user.save!
flash.alert = 'Your subscription has been updated!'
redirect_to root_url
end
def cancelsubscription
#user = current_user
#customer = Stripe::Customer.retrieve(#user.subscription.stripe_customer_token)
#customer.cancel_subscription()
current_user.save!
flash.alert = 'Your subscription has been cancelled successfully!'
redirect_to root_url
end
def showcard
#user = current_user
Stripe::Customer.retrieve(#user.subscription.stripe_customer_token).cards.all()
end
def changecard
#user = current_user
#customer = Stripe::Customer.retrieve(#user.subscription.stripe_customer_token)
card = #customer.cards.create({
:card => #user.subscription.stripe_customer_token
})
#customer.default_card = card
#customer.save
end
end
Subscription model:
belongs_to :plan
belongs_to :subscription
belongs_to :user
validates_presence_of :plan_id
validates_presence_of :email
attr_accessor :stripe_card_token, :paypal_payment_token
def save_with_payment
if valid?
if paypal_payment_token.present?
save_with_paypal_payment
else
save_with_stripe_payment
end
end
end
def paypal
PaypalPayment.new(self)
end
def save_with_paypal_payment
response = paypal.make_recurring
self.paypal_recurring_profile_token = response.profile_id
save!
end
def save_with_stripe_payment
customer = Stripe::Customer.create(description: email, plan: plan_id, card: stripe_card_token)
self.stripe_customer_token = customer.id
save!
rescue Stripe::InvalidRequestError => e
logger.error "Stripe error while creating customer: #{e.message}"
errors.add :base, "There was a problem with your credit card."
false
end
def payment_provided?
stripe_card_token.present? || paypal_payment_token.present?
end
def suspend_paypal
paypal.suspend
save
end
def reactivate_paypal
paypal.reactivate
save
end
end
The simplest way to do it would be to add extra lines to update the required column.
def cancelsubscription
#user = current_user
#customer = Stripe::Customer.retrieve(#user.subscription.stripe_customer_token)
#customer.cancel_subscription()
current_user.subscription.update_attributes(:cancelled => 1)
current_user.save!
flash.alert = 'Your subscription has been cancelled successfully!'
redirect_to root_url
end
However, ideally all this should happen within a model. From the controller you should just be telling the model to cancel the subscription.
So, this method could become something like:
#subscriptions_controller.rb
def cancelsubscription
current_user.subscription.cancel_stripe_subscription
flash.alert = 'Your subscription has been cancelled successfully!'
redirect_to root_url
end
#subscription.rb model
def cancel_stripe_subscription
customer = Stripe::Customer.retrieve(self.stripe_customer_token)
customer.cancel_subscription()
self.cancelled = 1
self.save!
end
Cant you update the Subscription table via an active_record query? Like this:
updateQuery = ActiveRecord::Base.connection.execute("UPDATE Subscription SET cancelled = 'Cancelled' WHERE user_id = #{#user.id}")
That'd update your subscription table and change the targetted field value to "Cancelled". Its not clear if this is a boolean or not. If it is, then the value should be "TRUE" instead of the "Cancelled" string i put in there.
If subscription succesfully saves, then you execute the query. But you'd have to make sure you put the query between a condition so that it only executes it when the user has cancelled the subscription, not every time its updated.
respond_to do |format|
if #subscription.save
if (something to tell the controller you are cancelling the subscription)
EXECUTE QUERY HERE
end
end
end

Rails controller method executes code in both the "if" and "else" statement

I have a friendship model that allows users to become friends in my Rails app. It stores the following data:
friendship_id (int), sender_id (int), receiver_id (int), sent_at (datetime), accepted (boolean), accepted_at (datetime)
The following controller method is for adding friends
def addfriend
if user_signed_in?
#sender = params[:sender]
#receiver = params[:receiver]
if Friendship.find_by(sender_id: #sender, receiver_id: #receiver).nil? &&
Friendship.find_by(sender_id: #receiver, receiver_id: #sender).nil?
#friend = Friendship.create(friendship_id: 0, sender_id: #sender, receiver_id: #receiver, sent_at: DateTime.now, accepted: false)
if #friend.save
flash[:success] = "Friend request sent"
redirect_to root_path
else
flash[:error] = "Oops, something went wrong."
redirect_to root_path
end
else
flash[:notice] = "Already friends with this person or friendship pending acceptance."
redirect_to root_path
end
end
end
What happens is the friend request gets sent, it will be there in the database and when I switch to the other user the request will be there, but the notification that pops up after the request was sent and the page reloads says "Already friends with this person or friendship pending acceptance." As if the request wasn't actually sent, even though it was. This even happens when all Friendships have been deleted in the database.
Any thoughts as to why this is happening? I want it to say "Friend request sent" when it does get sent, rather than what it is saying now.
redirect_to doesn't return from the method and continues the execution.
You need to do:
redirect_to root_path and return
or:
return redirect_to root_path
Try this
redirect_to :controller =>… , :action=>….
for example
def update
#tip = current_user.tips.find(params[:id])
#tip.attributes = params[:tip]
#tip.category_ids = params[:categories]
#tip.tag_with(params[:tags]) if params[:tags]
if #tip.save
flash[:notice] = 'Tip was successfully updated.'
redirect_to :controller=>'tips', :action => 'show', :id => #tip.permalink
else
render :action => 'edit'
end
end

Rails error messages always displayed, even before submit

My Account model:
def save_with_payment
if valid?
customer = Stripe::Customer.create(description: email, plan: plan_id, card: stripe_card_token)
self.stripe_customer_token = customer.id
save!
end
rescue Stripe::InvalidRequestError => e
logger.error "Stripe error while creating customer: #{e.message}"
errors.add :base, "There was a problem with your credit card."
false
end
My accounts controller:
# GET /accounts/new
# GET /accounts/new.json
def new
#account = Account.new
#company = #account.build_company
#user = #company.users.build
if #account.save_with_payment
redirect_to success_path, :notice => "Thank you for subscribing!"
else
render :new
end
respond_to do |format|
format.html # new.html.erb
format.json { render json: #account }
end
end
For some reason (only just started happening), the form always shows the validation errors (with or without submitting first)
why is this?
You execute #account.save_with_payment before submitting (and you don't pass parameters to this method). The code looks strange, usually there are two methods new and create, in first one you just find #account and pass it to view for form, in second one you save #account.
def new
#account = Account.new
end
def create
#account = Account.new(params[:account])
if #account.save
redirect_to #account
else
render :action => 'new'
end
end

Resources