Build AI into a Rails app with BoxCars
Tags: rails, ruby, ai
Published: 2023-02-28 15:35:25



![https://a-us.storyblok.com/f/1005616/4266x2843/ed4652f6a8/rails.jpg](https://a-us.storyblok.com/f/1005616/4266x2843/ed4652f6a8/rails.jpg)

Welcome to this step-by-step guide on how to add AI functionality to a Rails app using the open-source [BoxCars](https://www.boxcars.ai) 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](https://github.com/ralixjs/rails-ralix-tailwind)** as a sample app to work with. This starter app is a simple app with two models users and articles.

![https://a-us.storyblok.com/f/1005616/2600x2424/c8d58f374d/railsstarterapp.png](https://a-us.storyblok.com/f/1005616/2600x2424/c8d58f374d/railsstarterapp.png)

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:

```bash
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:

```bash
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:

```bash
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.

```ruby
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:

```erb
<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

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

And a **`_result.html.erb`** file with the response

```erb
<%= 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!


![Demo of our app](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cg5qj9jgu63efakz8jmv.gif)