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
Related
Hello I have an app where a user is invited as an attendee
In the attendee controller, when the attendee is created the user is created but not sent an invite to the system
attendees_controller.rb
def create
#attendee = Attendee.new(attendee_params)
#user = User.invite!({email: "#{#attendee.email}"}, current_user) do |u|
u.skip_invitation = true
end
#attendee.user_id = #user.id
respond_to do |format|
if #attendee.save
format.html { redirect_to meeting_url(#attendee.meeting), notice: "Attendee was successfully created." }
format.json { render :show, status: :created, location: #attendee }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #attendee.errors, status: :unprocessable_entity }
end
end
end
in the same controller i then have a send_invite
def send_invite
#attendee = Attendee.find(params[:attendee_id])
User.where(id: #attendee.user_id).deliver_invitation
redirect_to meeting_url(#attendee.meeting)
end
when i hit it via a button I get
NoMethodError in AttendeesController#send_invite
undefined method `deliver_invitation' for #<ActiveRecord::Relation
[devise_invitable][1] clearly states
If you want to create the invitation but not send it, you can set skip_invitation to true.
user = User.invite!(email: 'new_user#example.com', name: 'John Doe') do |u|
u.skip_invitation = true
end
# => the record will be created, but the invitation email will not be sent
When generating the accept_user_invitation_url yourself, you must use the raw_invitation_token. This value is temporarily available when you invite a user and will be decrypted when received.
accept_user_invitation_url(invitation_token: user.raw_invitation_token)
When skip_invitation is used, you must also then set the invitation_sent_at field when the user is sent their token. Failure to do so will yield “Invalid invitation token” error when the user attempts to accept the invite. You can set the column, or call deliver_invitation to send the invitation and set the column:
user.deliver_invitation
What am I missing?
[1]: https://github.com/scambra/devise_invitable#send-an-invitation-
I guess .deliver_invitation is an instance method on the User Model. (through devise_invitable).
In that case you would probably want something like this:
User.where(id: #attendee.user_id).each do |user|
user.deliver_invitation
end
Assuming deliver_invitation is an instance method of the User model, you can modify your send_invite method like below:
def send_invite
#attendee = Attendee.find(params[:attendee_id])
user = User.find(#attendee.user_id)
user.deliver_invitation
redirect_to meeting_url(#attendee.meeting)
end
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.
Im doing some testing on my app.
I have a form that accepts a city(autocompleted by city name), and some dates.
Because I have a autocomplete feature, I have to get the city_id by looking up the city by its display name.
def trip_params
params.require(:trip).permit(:start_date, :end_date).merge(:city_id => City.find_by_display(params[:trip][:city_id]).id)
end
The problem is if the user sumbits the form without a city. I get an error:
undefined method `id' for nil:NilClass
Because there was no record found. Whats a better way to structure this so that I can redirect back to 'new' if no city is entered?
create method just in case its helpful.
def create
#trip = current_user.trips.build(trip_params)
if #trip.save
flash[:success] = "Trip to #{#trip.city.name} added."
redirect_to root_path
else
flash.now[:error] = #trip.errors.full_messages
render 'new'
end
end
def create
if params[:trip][:city_id].blank?
flash[:error] = "some warning about the city"
render new
else
#trip = current_user.trips.build(trip_params)
if #trip.save
flash[:success] = "Trip to #{#trip.city.name} added."
redirect_to root_path
else
flash.now[:error] = #trip.errors.full_messages
render 'new'
end
end
end
or
def trip_params
if !params[:trip][:city_id].blank?
params.require(:trip).permit(:start_date, :end_date).merge(:city_id => City.find_by_display(params[:trip][:city_id]).id)
end
end
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
I'm developing an application with optional sign up. I want to allow users, with and without accounts, to be able to add links. How could I assign a user's session[user_id] to the user_id column of Link if they're signed in when creating a link?
Current code: user_id remains nil in either case
def create
#link = Link.new(params[:link])
if #link.save
flash[:notice] = "The link was successfully added"
redirect_to :action => :hot
else
redirect_to :action => :new
end
end
I'm imagining something like this..
def create
if session[:user_id]
##link equals new link params with user_id = session[:user_id]
else
#link = Link.new(params[:link])
end
if #link.save
flash[:notice] = "The link was successfully added"
redirect_to :action => :hot
else
redirect_to :action => :new
end
end
def create
#link = Link.new params[:link]
#link.user_id = session[:user_id] if session[:user_id]
if #link.save
redirect_to { action: 'hot' }, notice: 'The link was successfully added'
else
render :new
end
end
The link will be saved with params[:link] even if the user isn't logged-in.
Be cautious to use render, not redirect_to, when a validation fails (see if you want http://guides.rubyonrails.org/action_controller_overview.html)