Using RethinkDB with Ruby on Rails

    It’s easy to use RethinkDB with Ruby on Rails. This guide assumes some familiarity with Rails and ActiveRecord. We’ll be using NoBrainer—a RethinkDB ORM, which is an almost drop-in replacement for ActiveRecord.

    Before you start

    Getting started

    First, generate a new Rails application using NoBrainer:

    $ rails new nb_app
    $ cd nb_app
    $ echo "gem 'nobrainer'" >> Gemfile
    $ bundle install
    $ rails g nobrainer:install
    

    You can now generate models individually or use the scaffolding mechanism. For example, here’s a scaffold for an Article resource:

    $ rails g scaffold Article title:string text:string tags:array
    

    This yields the following model in app/models/article.rb:

    class Article
      include NoBrainer::Document
      include NoBrainer::Document::Timestamps
    
      field :title, :type => String
      field :text, :type => String
      field :tags, :type => Array
    end
    

    You’re now up and running with RethinkDB and Rails!

    Models in depth

    Unlike a relational database, RethinkDB doesn’t enforce types, so NoBrainer’s type annotations on the field are validators that are run just before a document is saved to the database. If you don’t want to specify the type for a field, you can use the dummy type object:

    $ rails g model User name:string:index user_data:object
    

    This allows the user_data field to contain any legal JSON value, while name must still be a valid string.

    class User
      include NoBrainer::Document
      include NoBrainer::Document::Timestamps
    
      field :name, :type => String, :index => true
      field :custom_data
    end
    

    The NoBrainer generator automatically includes the TimeStamps mixin that adds the fields created_on and updated_on. You’ll also notice this created a simple secondary index on the name field. In order to add the index to the database, you can use the Rake task:

    $ rake nobrainer:sync_schema
    

    Associations

    You can specify associations between models in the generator:

    $ rails g model Comment body:string liked:boolean \
        user:belongs_to article:belongs_to
    

    This will create the following model for comments:

    class Comment
      include NoBrainer::Document
      include NoBrainer::Document::Timestamps
    
      field :body, :type => String
      field :liked, :type => Boolean
      belongs_to :user
      belongs_to :article
    end
    

    If we go back into the Article model and add the has_many side of the association, it’s important to note that has_many associations in NoBrainer are read-only. The server doesn’t support transactions, so saving the members of the association is up to the developer.

    Validation

    We can also specify more in-depth validation on fields. We can modify the Article model in a few ways to ensure the data has the properties we expect:

    class Article
      include NoBrainer::Document
      include NoBrainer::Document::Timestamps
    
      has_many :comments # read only!
    
      field :title, :type => String
      field :text,  :type => String, :required => true
      field :tags,  :type => Array, :default => []
    
      validates :title, :length => { minimum: 5 }
    end
    

    NoBrainer runs the validations only when saving, but not when retrieving a document. This means you can always retrieve your data, but an invalid model won’t be saved to the database.

    Read about validation in NoBrainer for more details.

    Nested resources in views

    Since NoBrainer’s has_many associations are read-only, handling nested resources changes a little bit. For example, if Comments are nested in Articles, the comment form in the Article view would look like this:

    <%= form_for([@article, Comment.new(:article => @article)]) do |f| %>
      <b>Make a comment:</b><br>
      <%= f.label "I liked this article" %> <%= f.check_box :liked %><br>
      <%= f.text_area :body %>
      <%= f.submit %>
    <% end %>
    

    This just creates a new Comment and associates it with the current Article, rather than using the build method.

    Querying

    NoBrainer adds a light wrapper around ReQL queries. Here are some examples:

    # Find a specific document by its primary key
    Article.find "2FrYybOfzezVpT"
    
    # Find a comment from a user with 'bob' in its name sorted by the name.
    # Note: NoBrainer will use the :name index from User by default
    User.where(:name => /bob/).order_by(:name => :desc).to_a
    
    # Get two random comments that did not like the article
    Comment.where(:liked => false).sample(2)
    

    There is very comprehensive documentation of NoBrainer’s query language, and its capabilities. NoBrainer’s language is built on top of ReQL, so if you know how to do something in ReQL, it should be straightforward to translate it.

    And that’s it!

    You’re on your way with Ruby on Rails and RethinkDB! Be sure to check out additional resources for more information.