Expose Your Rails CRUD to the Browser with Databound

Share this article

Expose Your Rails CRUD to the Browser with Databound

As we go on building more and more JavaScript applications, the need for APIs will go on increasing. Writing a full-fledged API requires quite an amount of planning and time. But sometimes, all we require in an API are just common CRUD actions. Writing CRUD APIs for each and every resource can be quite a tedious and repetitive task. The Ruby community being what it is, some enterprising developers have taken a shot at solving the tedium. Today we will try a gem that will simplify creating these CRUD-based APIs within a Rails application. Let’s get started.

Creating a Rails application

We will create a basic Rails application with a Contact model. The application will use MRI Ruby, Rails 4.2, and SQLite to keep things simple. First of all, install MRI Ruby with RVM or rbenv.

Switch to Ruby and gem install rails to get the latest Rails gem. Now create a new Rails application, like so:

rails new databound_rails -T

After the application is generated, create a Contact model:

cd databound_rails
rails g model Contact name:string address:string city:string phone:string

Migrate the database:

rake db:migrate

Now we have Contact model in place. We will create the CRUD interface later.

Installing Databound

Now we will integrate Databound gem in our Rails application. We will also add ‘lodash-rails’ gem since Databound depends on it. Like so:

gem 'databound', '3.1.3'
gem 'lodash-rails', '3.10.1'

We are using ‘3.x’ version of ‘lodash’ for compatibility reasons.

Install both gems:

bundle install

Databound comes with a generator to add the required files into our application, so run it:

rails g databound:install

This adds databound.js to our asset pipeline. You’ll need to manually add ‘lodash’ in app/assets/javascripts/application.js, so that it’s picked up by the asset pipeline:

//= require lodash
//= require databound

Databound will already we added in application.js, but you need to remember to require ‘lodash’ before Databound.

Configuring Databound

Let’s use Databound with our Contact model. First, modify config/routes.rb to add Databound routes for Contact model:

Rails.application.routes.draw do
  databound :contacts
end

As you can see, we have added a Databound route for Contact model.

Databound will generate a controller named ContactsController automatically at runtime if it is not found. For simple models, this feature can save the time of writing controllers for each model. We can also specify API accessible columns here, like so:

databound :contacts, columns: [:name, :address, :city, :phone]

But we will create a ContactsController since we will explore more advanced options provided by Databound and hence will configure the columns in the controller itself.

Let’s ContactsController with following code:

class ContactsController < ApplicationController
  databound do
    model :contact

    columns :name, :address, :city, :phone
  end
end

Here we have defined the model as :contact, along with the columns that are accessible from the API here instead of doing so in routes.rb. Now when we invoke the API, only these specified columns can be accessed or modified.

Building the Frontend

We have our backend ready. Let’s create a simple jQuery-powered frontend for testing the API. First, add an action to our ContactsController for showing the Contacts page.

In app/controllers/contacts_controller.rb, add the following:

def index
end

You’ll need add a route for that action in config/routes.rb:

get 'contacts' => 'contacts#index'

Create the view for the action in app/views/contacts/index.html.erb with the following code:

<h1>Contacts</h1>
<table border="0">
  <tr>
    <td colspan="2"><h3>Create Contact</h3></td>
  </tr>
  <tr>
    <td><strong>Name:</strong></td>
    <td><input name="txtName" id="txtName" /></td>
  </tr>
  <tr>
    <td><strong>Address:</strong></td>
    <td><input name="txtAddress" id="txtAddress" /></td>
  </tr>
  <tr>
    <td><strong>City:</strong></td>
    <td><input name="txtCity" id="txtCity" /></td>
  </tr>
  <tr>
    <td><strong>Phone:</strong></td>
    <td><input name="txtPhone" id="txtPhone" /></td>
  </tr>
  <tr>
    <td colspan="2" align="center"><button name="createContact" id="createContact">Create Contact</button></td>
  </tr>
</table>

<table border="0" id="tblContacts">
  <thead>
    <th>Name</th>
    <th>Address</th>
    <th>City</th>
    <th>Phone</th>
  </thead>
  <tbody>
  </tbody>
</table>

Here we have created a simple interface to create a new Contact and show it in a table below. Now we will create contacts.js in app/assets/javascripts to bring the view to life:

var Contact = new Databound('/contacts');
$(document).ready(function(){
  $('#createContact').on('click', function() {
    Contact.create({ name: $('#txtName').val(), address: $('#txtAddress').val(), city: $('#txtCity').val(), phone: $('#txtPhone').val() }).then(function(new_contact) {
      var table = $('#tblContacts tbody');
      var row = "<tr>";
      row += "<td>" + new_contact.name + "</td>";
      row += "<td>" + new_contact.address + "</td>";
      row += "<td>" + new_contact.city + "</td>";
      row += "<td>" + new_contact.phone + "</td>";
      row += "</tr>";
      $(table).append(row);
    });
  });
});

We have defined the Contact Javascript object which we will be using for invoking CRUD actions on Contact model:

var Contact = new Databound('/contacts');

Next, there’s a simple event handler for the createContact button to call Contact.create, passing along the data from the Name, Address, City and Phone fields. Finally, append the created record to the table.

Let’s test if this works. Fire up the Rails server:

rails s

Hit http://localhost:3000/conatcts and create a few records. Records should be created and be visible in the table.

We have now successfully integrated Databound into our API. Let’s explore the other functions provided by Databound.

Searching API

Databound provides three client-side APIs for searching records. Let’s see them one by one.

where API

Contact.where({ name: 'Devdatta' }).then(function(contacts) {
 alert('Contacts named Devdatta');
});

Here we are invoking the where API to search for contacts that have name field matching with ‘Devdatta’. The matching records are returned in contacts object.

find API

Contact.find(1).then(function(contact) {
  alert('Contact ID 1: ' + contact.name);
});

Here we can find a specific contact with its primary key using the find API. We have passed the primary key as ‘1’ and received the relevant record in contact object.

findBy API

Contact.findBy({ name: 'Devdatta' }).then(function(contact) {
  alert('Contact named Devdatta from ' + contact.city);
});

findBy API is similar to where but you can specify only one field to search with. Here we are searching with name field matching with ‘Devdatta’. Matching record is returned in contact object.

We can also specify the default scope for searching as well using the extra_where_scopes while initializing the API. Like so –

var Contact = new Databound('/contacts',
  { city: 'Pune' },
  { extra_where_scopes: [{ city: 'Mumbai' }] }
);

Update & Delete API

Databound also provides update and destroy APIs to edit and delete records, respectively

Update API

Contact.update({ id: 1, name: 'John' }).then(function(contact) {
  alert("My name has changed. I'm " + contact.name);
});

Using Databound’s update API we can update the record’s fields as specified. Only accessible columns’ data will be updated as specified in the controller. Once updated, the contact object is returned with updated data.

Delete API

Contact.destroy(1).then(function(status) {
  if (status.success) alert('Contact deleted');
});

Records are deleted using the destroy API which accepts the primary key of the record as argument and returns the status as true or false.

Permit actions

Databound also allows specifying which actions are permitted based on certain conditions that can be invoked using API. For example:

permit(:update, :destroy) do |params, record|
  record.user_id == current_user.id
end

(Since we have not setup any authentication mechanism in our sample, this won’t work directly in our application)

Wrapping Up

Today we got a short introduction to Databound and how to use it in a Rails application. Many Rubyists may not like the way Databound works, since it binds your frontend code to the database rather tightly. However, there are sometimes cases where simplicity of solution wins over architectural purity. Databound merits a hard look is those kinds of scenarios. It is useful for fast prototyping of APIs and for small applications as well.

Hope you liked the tutorial.

Comments and suggestions welcome, as always.

Devdatta KaneDevdatta Kane
View Author

Devdatta Kane is a software developer and designer based in Pune, India. He works with Radinik Technologies building traceability solutions for a variety of industries. He is also the lead developer of refers2, a CRM for small businesses. He works in Ruby on Rails, but likes to dabble with various new technologies as well. An aspiring photographer and passionate traveler, he loves traveling on his motorcycle, capturing experiences through camera.

GlennG
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week