boxcars.ai
Article

Build AI into a Rails app with BoxCars

Tabrez Syed

Welcome to this step-by-step guide on how to add AI functionality to a Rails app using the open-source BoxCars gem!

BoxCars is a new gem that allows Ruby and Rails developers to integrate AI capabilities into their applications. In this guide, we’ll show you how easy it is to add a simple text-to-command user interface to a rails app. This will let the user ask their questions, and it will use AI to respond to the request.

Picking a rails app

In this guide, we'll be using the rails-railx-tailwind starter kit as a sample app to work with. This starter app is a simple app with two models users and articles.

To get started, go ahead and click the "Use this template" button on the rails-railx-tailwind GitHub page to create a new repository with the code. Then, clone your new repository using the following command:

git clone [url of your repo]

Before proceeding, ensure you have Ruby 3.2.0 installed on your system. You can install it using RVM with the following command:rvm install ruby-3.2.0

Now, run bin/setup to set up the app and bin/dev to start it in dev mode.

Adding BoxCars gem to your app

Now, let's add BoxCar AI to your app! First, add the BoxCars and dotenv gems to your Gemfile by adding the following lines:

gem "boxcars"
gem "dotenv"

Next, run bundle install to install the new gems.

The dotenv gem allows you to load environment variables from a .env file. To use the OpenAI LLM model, you must set the OPENAI_ACCESS_TOKEN environment variable. You can set the environment variable without using the dotenv gem.

Adding AI to the app

To demo the new functionality, we're going to add a new controller to our app by running the following command:

bin/rails generate controller boxcars

This will generate a new controller file named boxcars_controller.rb.

In BoxCars, each BoxCar represents a tool or API that the AI can use. In this demo, we’ll keep it simple and just use the Active Record BoxCar.

require 'boxcars'

class BoxcarsController < ApplicationController
 
    def index
        session[:qa] ||= []
    
    
        if params[:textcommand]
            # Instantiate the Active Record BoxCar
            ar_boxcar = Boxcars::ActiveRecord.new
          
            # The user's question is passed in via the textcommand parameter
            @question = params[:textcommand]
         
            # We send the question to AI and have it run the Active Record query
            @answer = ar_boxcar.run @question
      
            # We add the question, answer, and current time into an array
            # and store it in the session
            @qa = [@question, @answer, Time.now ]
            session[:qa].prepend @qa
         
        end
        @qalist = session[:qa]

        respond_to do |format|
            format.html
            format.turbo_stream
        end
    end
end

Next, we’ll create a new view that uses Turbo to take the user’s question, send it to AI, run the Active Record BoxCar and return the results.

Create a file named index.html.erb in the app/views/boxcars directory and add the following code:

<div class="flex items-center justify-between">
  <h1>BoxCars</h1>
  <%= link_to new_article_path, class: 'btn' do %>
    <%= heroicon "plus" %>
    New article
  <% end %>
</div>

<div class="flex items-center justify-center h-full">
  <%= form_with url: boxcars_path, data: { turbo_frame: "boxcars" }, class: "w-3/5 justify-center"  do |f| %>
    <div class="flex items-center justify-center h-full">
      <div class="flex absolute inset-0 items-center pl-3 pointer-events-none">
       
      </div>
      <%= f.text_field :textcommand, class: "search-input p-3 pl-10 text-sm", placeholder: "Ask BoxCars ..." %>
    </div>
    <div class="flex items-center justify-center h-full">
      <%=f.submit "Submit", :class =>  "rounded-md bg-indigo-500 px-3.5 py-2.5 text-center text-sm font-semibold text-white shadow-sm hover:bg-indigo-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-500" %>
    </div>
    
  
<% end %>
</div>

<%= turbo_frame_tag "boxcars", target: "_top" do %>
  

<% end %>

We’ll add the index.turb_stream.rb file with the following info

<%= turbo_stream.replace "boxcars" do %>
  <%= render "result", todo: @qa %>
<% end %>

And a _result.html.erb file with the response

<%= turbo_frame_tag "boxcars", target: "_top" do %>

<div id="qablock" class="flex items-center justify-center">
<ul role="list" class="space-y-2 py-4 sm:space-y-4 sm:px-6 lg:px-8  w-3/5">
  <% @qalist.each do |qa| %>
   <li class="bg-white px-4 py-6 shadow sm:rounded-lg sm:px-6">
              <div class="sm:flex sm:items-baseline sm:justify-between">
                <h3 class="text-base font-medium">
                
                  <span class="text-gray-900">Question:</span>
                  <span class="text-gray-600"><%=qa[0]%></span>
                           
                  
                </h3>
                <p class="mt-1 whitespace-nowrap text-sm text-gray-600 sm:mt-0 sm:ml-3">
                  <time datetime="2021-01-28T19:24"><%= distance_of_time_in_words(Time.now, qa[2])%></time>
                </p>
              </div>
              <div class="mt-4 space-y-6 text-sm text-gray-800">
              
              <p> <%= qa[1] %>
            
              </p></div>
            </li>
           
    <% end %>
</ul>
</div>
<div class="justify-center w-3/5">

</div>
<% end %>

Finally, add a new route to your routes.rb file by adding the following line:

ruby

match 'boxcars', to: 'boxcars#index', via: [:get, :post]

Voila! AI lets your users ask questions directly.

In this demo, we’ve used the Active Record BoxCar, which uses OpenAI to translate the user’s text into an Active Record query. By default, the actions are read-only so no changes are made to the database. PS: It's even forgiving of typos!

← Back to Blog

Want these insights delivered? Subscribe below.