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:
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!
Top comments (0)