DEV Community

hooopo wang
hooopo wang

Posted on

Build a Rails App with TiDB and the ActiveRecord TiDB Adapter

TiDB is an open-source NewSQL database that supports Hybrid Transactional and Analytical Processing (HTAP) workloads. It is MySQL compatible and features horizontal scalability, strong consistency, and high availability.

I assumed using TiDB as a backend storage layer of Ruby on Rails application perhaps is a great way to manage storages into one place.

This post describes how to get started and how to use TiDB as backend of Ruby on Rails applications for developers.

Example source codes are available at rails-tidb in GitHub.

Setting up local TiDB server

Install tiup

$ curl --proto '=https' --tlsv1.2 -sSf | sh
Enter fullscreen mode Exit fullscreen mode

Starting TiDB playground

$ tiup playground  nightly
Enter fullscreen mode Exit fullscreen mode

Then, we can connect to the TiDB instance just as connecting to MySQL.

mysql --host --port 4000 -u root -p
Enter fullscreen mode Exit fullscreen mode

Initialize Ruby on Rails application

$ ruby -v
ruby 2.7.0

$ rails -v
Rails 6.1.4

$ rails new tidb-rails --database=mysql --api
Enter fullscreen mode Exit fullscreen mode

Add activerecord-tidb-adapter to Gemfile

$ bundle add activerecord-tidb-adapter --version "~> 6.1.0"
Enter fullscreen mode Exit fullscreen mode

After creating a new app, edit config/database.yml to configure connection settings to TiDB.

default: &default
  adapter: tidb
  encoding: utf8mb4
  collation: utf8mb4_general_ci
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  port: 4000
    tidb_enable_noop_functions: ON
  username: root

  <<: *default
  database: tidb_rails_development
Enter fullscreen mode Exit fullscreen mode

No need to add additional database configurations to use TiDB. It’s ready to use TiDB as a database of the Rails app!

Create a database

$ bundle exec rails db:create
Created database 'tidb_rails_development'
Created database 'tidb_rails_test'
Enter fullscreen mode Exit fullscreen mode

Manipulate TiDB data through Rails app

Defining Model using rails g command.

$ bundle exec rails g model user email:string name:string gender:integer
$ vim ./db/migrate/20210826174523_create_users.rb # edit
Enter fullscreen mode Exit fullscreen mode


class CreateUsers < ActiveRecord::Migration[6.1]
  def change
    create_table :users do |t|
      t.string :email, index: {unique: true}
      t.string :name
      t.integer :gender

Enter fullscreen mode Exit fullscreen mode

Then, apply database migration.

$ bundle exec rails db:migrate
== 20210826174523 CreateUsers: migrating ======================================
-- create_table(:users)
   -> 0.1717s
== 20210826174523 CreateUsers: migrated (0.1717s) =============================
Enter fullscreen mode Exit fullscreen mode

Launch Rails console to play with the app.

$ bundle exec rails c
Running via Spring preloader in process 13378
Loading development environment (Rails
irb(main):001:0> 30.times.each { |i| User.create!(email: "user-#{i}", name: "user-#{i}", gender: i % 3) }
   (1.2ms)  select version()
  User Create (93.5ms)  INSERT INTO `users` (`email`, `name`, `gender`, `created_at`, `updated_at`) VALUES ('', 'user-0', 0, '2021-08-26 17:50:40.661945', '2021-08-26 17:50:40.661945')
=> 30
irb(main):002:0> User.count
   (8.9ms)  SELECT COUNT(*) FROM `users`
=> 30
irb(main):003:0> User.first
  User Load (5.8ms)  SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
=> #<User id: 1, email: "", name: "user-0", gender: 0, created_at: "2021-08-26 17:50:40.661945000 +0000", updated_at: "2021-08-26 17:50:40.661945000 +0000">
Enter fullscreen mode Exit fullscreen mode


TiDB offers MySQL interfaces which can be used as backend database layers of Ruby on Rails applications.

We can use ActiveRecord ORM directly, or use activerecord-tidb-adpater, a lightweight extension of ActiveRecord that supports several rails versions, including 5.2, 6.1, and 7.0.

The activerecord-tidb-adapter provides compatible patches and some tidb-specific functions, such as Sequence.

Top comments (2)

yahonda profile image
Yasuo Honda

Great introduction article.
Based on the document and show collation output from TiDB 5.1.1, TiDB does not support utf8mb4_general_ci.
Then this database.yml may need to be updated as follows?

  • Current
  collation: utf8mb4_general_ci
Enter fullscreen mode Exit fullscreen mode
  • To
  collation: utf8mb4_bin
Enter fullscreen mode Exit fullscreen mode
Server version: 5.7.25-TiDB-v5.1.1 TiDB Server (Apache License 2.0) Community Edition, MySQL 5.7 compatible

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MySQL [(none)]> show collation;
| Collation   | Charset | Id   | Default | Compiled | Sortlen |
| utf8mb4_bin | utf8mb4 |   46 | Yes     | Yes      |       1 |
| latin1_bin  | latin1  |   47 | Yes     | Yes      |       1 |
| binary      | binary  |   63 | Yes     | Yes      |       1 |
| ascii_bin   | ascii   |   65 | Yes     | Yes      |       1 |
| utf8_bin    | utf8    |   83 | Yes     | Yes      |       1 |
5 rows in set (0.00 sec)

MySQL [(none)]>
Enter fullscreen mode Exit fullscreen mode
hooopo profile image
hooopo wang

Yes. when new_collations_enabled_on_first_bootstrap = true is set, utf8mb4_general_ci is avaliable. I missed this tidb cluster setting.