Ask A Question

Notifications

You’re not receiving notifications from this thread.

Rails Braintree couldn't update

Lee Terng Gio asked in Rails

I'm implementing Braintree Subscription Payment into my rails app. I've encounter some issue when trying to update subscription information in my database. When I make a payment, it's successfully created and saved into Braintree. The transaction was also created and saved into my database. The only problem is it couldn't update the payment information such as braintree_id, braintree_subscription_id etc in the User.

Below is my Subscriptions Controller:

class SubscriptionsController < ApplicationController
  before_action :logged_in_user, only: [:new, :create]

  def new
    @plans = Braintree::Plan.all
  end

  def create
    if current_user.braintree_id?
      customer = Braintree::Customer.find(current_user.braintree_id)
    else
      result = Braintree::Customer.create(
        email: current_user.company_email,
        payment_method_nonce: params[:payment_method_nonce]
      )
      customer = result.customer
      current_user.update(braintree_id: customer.id)

    end

    result = Braintree::Subscription.create(
      payment_method_token: customer.payment_methods.find{ |pm| pm.default? }.token,
      plan_id: params[:plan_id],
    )

    result.subscription.transactions.each do |transaction|
      current_user.transactions.create(braintree_transaction_id: transaction.id,
        plan_name: params[:plan_name],
        price: transaction.amount.to_f,
        start_date: transaction.subscription_details.billing_period_start_date,
        end_date: transaction.subscription_details.billing_period_end_date,
        subscription_id: result.subscription.id,
        )
    end

    current_user.update(braintree_subscription_id: result.subscription.id, next_billing_date: result.subscription.next_billing_date,
    billing_period_start_date: result.subscription.billing_period_start_date,
    billing_period_end_date: result.subscription.billing_period_end_date,
    status: result.subscription.status,
    next_billing_period_amount: result.subscription.next_billing_period_amount,
    paid_through_date: result.subscription.paid_through_date,
    plan_id: params[:plan_id],
    plan_name: params[:plan_name])

    redirect_to @current_user, notice: "You have been subscribed"
  end
end

I've tried to manually update the information in the console, and everything works well. Below are the output that when making a new payment, it rollback and couldn't update the User. While the Transaction was created and saved into database.

Started POST "/subscription.213" for 61.6.143.87 at 2017-12-14 07:57:55 +0000
Processing by SubscriptionsController#create as 
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"FHwbQSfiinjfskBG3Iec8C0gKuGIeOQDmBnjJu4fpEQwsrmsewHYvgAFIpKVguehm+TZAjHrfd8Ya6CWYPX1Rw==", "plan_id"=>"monthly", "plan_name"=>"monthly", "payment_method_nonce"=>"0986895d-aab4-01b3-5829-778101fa0ebb"}
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1  [["id", 213]]
I, [2017-12-14T07:57:56.724260 #10346]  INFO -- : [Braintree] [14/Dec/2017 07:57:56 UTC] POST /merchants/wt92v8tk2hn8j7kg/customers 201
   (0.1ms)  begin transaction
  User Exists (0.3ms)  SELECT  1 AS one FROM "users" WHERE (LOWER("users"."company_email") = LOWER('test-11@railstutorial.org') AND "users"."id" != 213) LIMIT 1
   (0.1ms)  rollback transaction
I, [2017-12-14T07:57:57.747920 #10346]  INFO -- : [Braintree] [14/Dec/2017 07:57:57 UTC] POST /merchants/wt92v8tk2hn8j7kg/subscriptions 201
   (0.0ms)  begin transaction
  SQL (0.3ms)  INSERT INTO "transactions" ("braintree_transaction_id", "plan_name", "price", "start_date", "end_date", "subscription_id", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)  [["braintree_transaction_id", "38273ws4"], ["plan_name", "monthly"], ["price", 9.0], ["start_date", "2017-12-14"], ["end_date", "2018-01-13"], ["subscription_id", "7882v6"], ["user_id", 213], ["created_at", "2017-12-14 07:57:57.780968"], ["updated_at", "2017-12-14 07:57:57.780968"]]
   (8.8ms)  commit transaction
   (0.1ms)  begin transaction
  User Exists (0.3ms)  SELECT  1 AS one FROM "users" WHERE (LOWER("users"."company_email") = LOWER('test-11@railstutorial.org') AND "users"."id" != 213) LIMIT 1
   (0.1ms)  rollback transaction
Redirected to https://kiplr-ternggio.c9users.io/users/213
Completed 302 Found in 2257ms (ActiveRecord: 10.4ms)

This thing works perfectly in my other app which using Devise. I didn't use Devise in this app and I'm not sure what really cause this issue. It really appreciated if somebody point me some direction.

Reply

Hi Lee,

You probably have a validation on the user model or transaction model that's not being satisfied. Can you post any validations you have on your user and transaction model?

You can also use the byebug gem and place byebug right before the transaction that fails. Then try another subscription and this time when byebug is triggered, try creating the transaction there manually and see what error is raised.

Reply

Below is the User model:

    validates :company_name, presence: true, length: {maximum: 50}
    VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
        validates :company_email, presence: true, length: {maximum: 255}, format: { with: VALID_EMAIL_REGEX }, uniqueness: { case_sensitive: false }
    validates :company_contact, presence: true, length: {maximum: 15}
    validates :term, presence: true
    has_secure_password
    validates :password, presence: true, length: { minimum: 6 }
    validates_confirmation_of :password

Below is my db/seed

User.create!(company_name:  "Example User",
             company_email: "example@railstutorial.org",
             company_contact: "011999484",
             password:              "foobar",
             password_confirmation: "foobar",
             term:     true,
             activated: true,
             activated_at: Time.zone.now)

99.times do |n|
  company_name  = "Example user"
  company_email = "example-#{n+1}@railstutorial.org"
  company_contact = "0119999494"
  password = "password"
  User.create!(company_name:  company_name,
              company_email: company_email,
              company_contact: company_contact,
              password:              password,
              password_confirmation: password,
              term: true,
              activated: true,
              activated_at: Time.zone.now)
end

When I run rake db:seed, everything works well, and I can login using the password as "password", but when run user.valid?, it gives false and the errors messages show {:password=>["can't be blank", "is too short (minimum is 6 characters)"]}

Reply

What are you using to authenticate your users in this app if you're not using Devise? The error shown is clearly that it's expecting a password, and your validations on your user model also state you need password info when saving/updating a user.

I think you need to restructure your models some... your user model really needs to be focused on just the users information needed to login. Everything else needs to be in their own model that is associated with the user model.

So instead of putting a users company in the user model, create a company model and then depending on your needs, either do a has_one or has_many association between the user and company.

You also need a subscription model that will take care of keeping track of a users subscription. You may also consider a payment_source model that will keep track of the braintree_id.

Ideally, for what you're wanting to accomplish, you shouldn't need to save anything to the user model when you're creating a transaction.

Reply
Join the discussion
Create an account Log in

Want to stay up-to-date with Ruby on Rails?

Join 81,842+ developers who get early access to new tutorials, screencasts, articles, and more.

    We care about the protection of your data. Read our Privacy Policy.

    Screencast tutorials to help you learn Ruby on Rails, Javascript, Hotwire, Turbo, Stimulus.js, PostgreSQL, MySQL, Ubuntu, and more.

    © 2024 GoRails, LLC. All rights reserved.