Skip to main content

Rails Braintree couldn't update

Rails • Asked by Lee Terng Gio

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('[email protected]') 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('[email protected]') 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.


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.


Below is the User model:

    validates :company_name, presence: true, length: {maximum: 50}
    VALID_EMAIL_REGEX = /\A[\w+\-.][email protected][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: "[email protected]",
             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)"]}


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.


Login or Create An Account to join the conversation.

Subscribe to the newsletter

Join 27,623+ developers who get early access to new screencasts, articles, guides, updates, and more.

    By clicking this button, you agree to the GoRails Terms of Service and Privacy Policy.

    More of a social being? We're also on Twitter and YouTube.