DEV Community

Cover image for Adding Plaid to Your Rails Application
Duarte Martins
Duarte Martins

Posted on

Adding Plaid to Your Rails Application

This is a repost of the orignal article at: https://popadex.com/2024/05/19/adding-plaid-to-rails-app

Integrating Plaid into your Rails application allows you to link bank accounts and retrieve financial data, providing a seamless way to access and manage financial information. This guide will walk you through the process of adding Plaid to your Rails app, assuming you have TailwindCSS already set up for styling. We will cover the necessary steps to configure the backend, set up routes, and create views for linking bank accounts and displaying account details.

Step 1: Add the Plaid Gem

First, you need to add the Plaid gem to your Gemfile. This gem provides the necessary methods to interact with the Plaid API.

Gemfile:

gem 'plaid' 
Enter fullscreen mode Exit fullscreen mode

Then, run:

bundle install 
Enter fullscreen mode Exit fullscreen mode

Step 2: Set Up Plaid Configuration

Next, you need to initialize Plaid in your application. Add the following code to your initializers:

config/initializers/plaid.rb:

# Initialize Plaid configuration plaid_config = Plaid::Configuration.new plaid_config.server_index = Plaid::Configuration::Environment["sandbox"] # or another environment as needed plaid_config.api_key["PLAID-CLIENT-ID"] = Rails.application.credentials.dig(:development, :plaid, :client_id) plaid_config.api_key["PLAID-SECRET"] = Rails.application.credentials.dig(:development, :plaid, :secret) # Create an API client instance api_client = Plaid::ApiClient.new(plaid_config) # Create a Plaid API instance to use across the application PlaidClient = Plaid::PlaidApi.new(api_client) api_client.create_connection do |builder| builder.use Faraday::Response::Logger end 
Enter fullscreen mode Exit fullscreen mode

Step 3: Set Up Routes

Add the necessary routes to your config/routes.rb file:

Rails.application.routes.draw do root 'plaid#index' post 'plaid/create_link_token', to: 'plaid#create_link_token' post 'plaid/exchange_public_token', to: 'plaid#exchange_public_token' get 'plaid/accounts', to: 'plaid#accounts' end 
Enter fullscreen mode Exit fullscreen mode

Step 4: Create the Plaid Controller

Create a controller to handle Plaid operations:

app/controllers/plaid_controller.rb:

class PlaidController < ApplicationController before_action :authenticate_user! protect_from_forgery with: :null_session # to handle CSRF protection for API requests def index end def create_link_token user = current_user link_token_create_request = Plaid::LinkTokenCreateRequest.new({ user: { client_user_id: user.id.to_s }, client_name: 'Your App Name', products: %w[auth transactions], country_codes: ['US'], language: 'en' }) begin link_token_response = PlaidClient.link_token_create(link_token_create_request) render json: { link_token: link_token_response.link_token } rescue Plaid::ApiError => e Rails.logger.error("Plaid API error: #{e.response_body}") render json: { error: e.response_body }, status: :internal_server_error end end def exchange_public_token Rails.logger.debug("Received public_token: #{params[:public_token]}") if params[:public_token].blank? Rails.logger.error('No public_token received') return render json: { error: 'No public_token received' }, status: :bad_request end begin exchange_token(params[:public_token]) render json: { message: 'Bank account linked successfully.' }, status: :ok rescue Plaid::ApiError => e Rails.logger.error("Plaid API error: #{e.response_body}") render json: { error: e.response_body }, status: :internal_server_error end end def exchange_token(public_token) request = Plaid::ItemPublicTokenExchangeRequest.new({ public_token: public_token }) response = PlaidClient.item_public_token_exchange(request) access_token = response.access_token item_id = response.item_id Rails.logger.debug("Access token: #{access_token}") Rails.logger.debug("Item ID: #{item_id}") if current_user.update(plaid_access_token: access_token, plaid_item_id: item_id) Rails.logger.debug('Access token and item ID saved successfully.') Rails.logger.debug("Current user after save: #{current_user.inspect}") else Rails.logger.error("Failed to save access token and item ID. Errors: #{current_user.errors.full_messages.join(', ')}") end end def accounts access_token = current_user.plaid_access_token if access_token.blank? flash[:error] = 'Access token is missing. Please link your account again.' return redirect_to root_path end begin accounts_request = Plaid::AccountsGetRequest.new({ access_token: access_token }) accounts_response = PlaidClient.accounts_get(accounts_request) @accounts = accounts_response.accounts rescue Plaid::ApiError => e Rails.logger.error("Plaid API error: #{e.response_body}") flash[:error] = "Plaid API error: #{e.response_body}" return redirect_to root_path rescue StandardError => e Rails.logger.error("Internal server error: #{e.message}") flash[:error] = 'Internal server error' return redirect_to root_path end end end 
Enter fullscreen mode Exit fullscreen mode

Step 5: Create the View

Create a view to display the link button and account details.

app/views/plaid/index.html.erb:

<!DOCTYPE html> <html class="dark"> <head> <title>Account Details</title> </head> <body class="bg-white dark:bg-gray-900 text-black dark:text-white"> <div class="container mx-auto p-4"> <h1 class="text-3xl font-bold mb-4">Link Your Bank Account</h1> <button id="link-button" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded dark:bg-gray-900 dark:hover:bg-gray-700 dark:text-white">Link Account</button> <script src="https://cdn.plaid.com/link/v2/stable/link-initialize.js"></script> <script> document.getElementById('link-button').onclick = function() { var csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content'); fetch('/plaid/create_link_token', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': csrfToken }, body: JSON.stringify({}) }) .then(response => response.json()) .then(data => { if (data.error) { console.error('Error:', data.error); return; } var linkHandler = Plaid.create({ token: data.link_token, onSuccess: function(public_token, metadata) { fetch('/plaid/exchange_public_token', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': csrfToken }, body: JSON.stringify({ public_token: public_token }) }) .then(response => response.json()) .then(data => { if (data.error) { console.error('Error:', data.error); return; } window.location.href = '/plaid/accounts'; }); }, onExit: function(err, metadata) { console.log('Plaid link exit', err, metadata); } }); linkHandler.open(); }) .catch(error => { console.error('Fetch error:', error); }); }; </script> </div> </body> </html> 
Enter fullscreen mode Exit fullscreen mode

app/views/plaid/accounts.html.erb:

<!DOCTYPE html> <html class="dark"> <head> <title>Account Details</title> </head> <body class="bg-white dark:bg-gray-900 text-black dark:text-white"> <div class="container mx-auto p-4"> <h1 class="text-3xl font-bold mb-4">Account Details</h1> <% if @error %> <div class="bg-red-500 text-white p-2 rounded mb-4"> Error: <%= @error %> </div> <% else %> <div class="overflow-x-auto"> <table class="min-w-full bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-700"> <thead> <tr class="bg-gray-200 dark:bg-gray-700"> <th class="py-2 px-4 border-b border-gray-300 dark:border-gray-600">Name</th> <th class="py-2 px-4 border-b border-gray-300 dark:border-gray-600">Type</th> <th class="py-2 px-4 border-b border-gray-300 dark:border-gray-600">Subtype</th> <th class="py-2 px-4 border-b border-gray-300 dark:border-gray-600">Mask</th> <th class="py-2 px-4 border-b border-gray-300 dark:border-gray-600">Balance</th> </tr> </thead> <tbody> <% @accounts.each do |account| %> <tr class="border-b border-gray-300 dark:border-gray-700"> <td class="py-2 px-4"><%= account.name %></td> <td class="py-2 px-4"><%= account.type %></td> <td class="py-2 px-4"><%= account.subtype %></td> <td class="py-2 px-4"><%= account.mask %></td> <td class="py-2 px-4"><%= number_to_currency(account.balances.available) %></td> </tr> <% end %> </tbody> </table> </div> <% end %> </div> </body> </html> 
Enter fullscreen mode Exit fullscreen mode

Conclusion

By following these steps, you can integrate Plaid into your Rails application to link bank accounts and display account details. This guide covers the necessary configuration, routes, controller actions, and views to set up Plaid. Make sure to handle API keys securely and configure the environment properly for production.

Top comments (1)

Collapse
 
afaq_shahid profile image
Afaq Shahid Khan

You write it in such a simple form. Thanks