undefined method `stripe_id' for nil:NilClass - ruby-on-rails

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

Related

How to pass javascript variable from Rails view to action

I have a list of user emails in a bit of Javascript code in my view that I have created for my action. The view is in haml format.
I want to press a submit button on a form and access this list of emails in the same action or another action.
I've tried using form_tag, form_for and just normal html forms, however I keep running into different issues. I've also tested with link_to and button_to tags.
Here's what we have for the Action:
module RailsAdmin
module Config
module Actions
class BulkProperties < RailsAdmin::Config::Actions::Base
RailsAdmin::Config::Actions.register(self)
register_instance_option :collection do
true
end
register_instance_option :http_methods do
[:get, :put]
end
register_instance_option :controller do
proc do
#all_users = User.all
#all_properties = UserProperty.all
#all_roles = Role.all
binding.pry
if request.get? # EDIT
respond_to do |format|
format.html { render #action.template_name }
format.js { render #action.template_name, layout: false }
end
elsif request.put? # UPDATE
binding.pry #Just testing this
end
end
register_instance_option :link_icon do
'icon-lock'
end
end
end
end
end
And this the part of my view giving me issues:
%form
.multiselect-form
.wrapper{"data-children-count" => "1"}
%select.collection{:multiple => "multiple", :id => "multi"}
%hr/
%h1 List of user properties
-#all_properties.each do |prop|
%input{:name => prop.name+"checkbox", :type => "checkbox", :id => prop.name+"checkbox"}
#{prop.name}
%input{:name => prop.name, :type => "text", :id => prop.name}
%br
%input{:name => "submit", :type => "submit", :formaction => 'http://localhost:3000/admin/user/bulk_properties?Application=8&Company=1&locale=en', :method => 'put'}
%br/
%br/
The outcome is that I am led to a CanCan issue where I'm getting 'You are not authorized...'. This is because the url actually ends up holding the parameters and so it tries to redirect me to a webpage that doesn't exist.
I implemented an action that uploads a file with js to S3 and sets the value of a form field with javascript then i use that url on the rails admin action.
I'm pasting it all because in the past that would have helped me in these cases by comparing my approach to a working approach.
Here are the relevant (simplified)files:
# app/views/rails_admin/main/update_orders_and_line_items.html.haml
= form_tag(method: :post) do
= hidden_field_tag 'uploaded-file-url', '', id: 'uploaded-file-url'
= submit_tag 'Submit', class: 'action-button-pink'
# app/assets/javascripts/google_cloud_storage_field.js
let url = get_url(fileInput);
let valueField = $('#uploaded-file-url');
valueField.val(url);
# lib/rails_admin/config/actions/update_orders_and_line_items.rb
module RailsAdmin
module Config
module Actions
class UpdateOrdersAndLineItems < RailsAdmin::Config::Actions::Base
# Might cause random bugs if enabled
register_instance_option :pjax? do
false
end
register_instance_option :http_methods do
[:post, :get]
end
register_instance_option :controller do
proc do
if request.post?
url = params['uploaded-file-url']
do_stuff_with(url)
elsif request.get?
# [...]
end
end
end
end
end
end
end
I believe the source of your bug is using the %form tag, the default method of a form is GET and thats why your browser tries to redirect you to some page, if you use like i did form_tag(method: :post) and make sure the emails are on the hidden_field_tag value, you'll get your list on the action.rb

display braintree errors on fail

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.

Mailchimp gem double_optin false not working

double opt-in confirmation email still goes through, any idea what's wrong? Was having problems with the gibbon gem, so opted for mailchimp gem instead.
Gemfile
gem "mailchimp-api", "~> 2.0.4"
application_controller.rb
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_action :setup_mcapi
def setup_mcapi
#mc = Mailchimp::API.new('mailchimp api key goes here')
#list_id = "list id goes here"
end
end
welcome_controller.rb
class WelcomeController < ApplicationController
def index
end
def subscribe
email = params[:email][:address]
if !email.blank?
begin
#mc.lists.subscribe(#list_id, {'email' => email}, 'double_optin' => false)
end
respond_to do |format|
format.json{render :json => {:message => "Success!"}}
end
rescue Mailchimp::ListAlreadySubscribedError
respond_to do |format|
format.json{render :json => {:message => "#{email} is already subscribed to the list"}}
end
rescue Mailchimp::ListDoesNotExistError
respond_to do |format|
format.json{render :json => {:message => "The list could not be found."}}
end
rescue Mailchimp::Error => ex
if ex.message
respond_to do |format|
format.json{render :json => {:message => "There is an error. Please enter valid email id."}}
end
else
respond_to do |format|
format.json{render :json => {:message => "An unknown error occurred."}}
end
end
end
else
respond_to do |format|
format.json{render :json => {:message => "Email Address Cannot be blank. Please enter valid email id."}}
end
end
end
end
index.html.erb
<h3>Add a New Member</h3>
<p>Please enter your email address to subscribe to our newsletter.</p>
<%= form_tag('/welcome/subscribe', method: "post", id: "welcome", remote: "true") do -%>
<%= email_field(:email, :address, {id: "email", placeholder: "email address"}) %>
<%= submit_tag("Subscribe") %>
<% end %>
<div id="response">Response Will be displayed here</div>
routes.rb
Rails.application.routes.draw do
root 'welcome#index'
post 'welcome/subscribe' => 'welcome#subscribe'
end
From mailchimp-api document
subscribe(id, email, merge_vars = nil, email_type = 'html', double_optin = true, update_existing = false, replace_interests = true, send_welcome = false) ⇒ Hash
The double_optin is the parameter which will be passed directly not like what you did.
So, it will be:
#mc.lists.subscribe(#list_id, email, nil, 'html', false)
The answer above kept giving me errors, this worked for me:
#mc.lists.subscribe(#list_id, { "email" => email }, merge_vars = nil, email_type = 'html', double_optin = false)

Can't unfollow user because of Postgres

Rails 3.2, Twitter App
UPDATE: Sovled but any idea why it might work once, then when i try it again, I get Unknown key: #<User:0x007f9a5a946708> On line 16 users_controller.rb for #user. If i update a status or re-login its fine.
SOLUTION: After adding a notice: "Added", redirect_to_path under each if/else it worked fine. I haven't been able to produce an error for "user not found" tho.
I got a form_for, I type in :username, it follows or unfollows. Unfollow don't work. Looks like this.
Error
PG::UndefinedTable: ERROR: missing FROM-clause entry for table "id"
LINE 1: DELETE FROM "relationships" WHERE "id"."follower_id" = 1 AND...
^
: DELETE FROM "relationships" WHERE "id"."follower_id" = 1 AND "id"."followed_id" = 2
id is missing? So I think the problem is in relationship_controller.rb
/users/buddies.html.erb
<%= form_for :username, :url => {:action => :buddies} do |f| %>
<%= f.text_field #user, placeholder: "username" %>
<%= f.submit "Add/Subtract" %>
<% end %>
users_controller.rb
#user = User.find_by_username(params[:username])
if #user
unless #user.blank?
if current_user.following? #user
current_user.unfollow #user
else
current_user.follow #user
end
else
flash[:error] = "stupid error";
end
end
user.rb
def following? user
self.followeds.include? user
end
def follow user
Relationship.create follower_id: self.id, followed_id: user.id
end
def unfollow user
Relationship.delete follower_id: self.id, followed_id: user.id
end
relationships_controller.rb
def create
#relationship = Relationship.new(params[:relationship])
##relationship.followed_id = params[:followed_id]
#relationship.follower_id = current_user.id
if #relationship.save
redirect_to buddies_path, notice: "Phriend added"
else
flash[:error] = "Phriend not added";
redirect_to buddies_path
end
end
def delete
#relationship = Relationship.find(params[:id])
#relationship.delete
redirect_to buddies_path, notice: "Phriend subtracted"
end
So that's a lot of words, but look in Relationship.delete.. what needs to change there?
Relationship.delete is expecting an id. Try something like:
# app/models/user.rb
def unfollow user
Relationship.where(:follower_id => self.id, :followed_id => user.id).first.delete
end
Or, perhaps a bit clearer, if followeds are relationships:
def unfollow user
self.followeds.where(:followed_id => user.id).first.delete
end
#didn't work for #ladiesman217

Where and how to handle Stripe exceptions?

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

Resources