Sử dụng Arel trong Rails

Giới thiệu

Hầu hết các developer đều quen thuộc với ActiveRecord queries, Nhưng không biết hoặc không biết nhiều với Arel. Vậy Arel nó là gì? - Arel là thư viện đã được giới thiệu trong Rails 3, công cụ quản lý truy vấn dữ liệu SQL, nó cho phép bạn customize các câu queries, bạn không cần phải sử dụng các SQL plain.

  • Arel là một công cụ tuyệt vời, nó cung cấp những câu query đầy đủ, nó giúp cho việc truy vấn dữ liêu của ta được rõ ràng và minh bạch

Cách sử dụng trong ứng dụng rails

  1. Tạo Data Ta tạo 2 table bên dưới để dùng để minh họa cho các câu truy vấn

    ActiveRecord::Schema.define(version: 20180128081302) do
    
     create_table "payments", force: :cascade do |t|
       t.string "order_id"
       t.float "amount"
       t.integer "user_id"
       t.datetime "created_at", null: false
       t.datetime "updated_at", null: false
       t.index ["user_id"], name: "index_payments_on_user_id"
     end
    
     create_table "users", force: :cascade do |t|
       t.string "name"
       t.datetime "created_at", null: false
       t.datetime "updated_at", null: false
       t.string "email"
       t.string "password_digest"
       t.string "status"
     end
    
    end
    
  2. Arel Table

    Class mà ta sử dụng chủ yếu khi làm việc với Arel đó là Arel::Table. Để get Arel::Table instance của một model ta có cách:

    • Sử dụng class method của ActiveRecord
    User.arel_table
    
    • Sử dụng constructor của class Arel::table
    Arel::Table.new(:users)
    

  1. Một số câu truy vấn cơ bản
    • Truy vấn với điều kiện where Ta get tất cả các User có password_digets is nil
          User.where(users[:password_digest].eq nil)
          User Load (0.4ms)  SELECT  "users".* FROM "users" WHERE "users"."password_digest" IS NULL LIMIT ?  [["LIMIT", 11]]
      
    • Comparison operators =, !=, <, >, <=, >=, IN:
users.where(users[:age].eq(10)).project(Arel.sql('*'))
=> SELECT * FROM "users"  WHERE "users"."age" = 10

users.where(users[:age].not_eq(10)).project(Arel.sql('*'))
=> SELECT * FROM "users"  WHERE "users"."age" != 10

users.where(users[:age].lt(10)).project(Arel.sql('*'))
=> SELECT * FROM "users"  WHERE "users"."age" < 10

users.where(users[:age].gt(10)).project(Arel.sql('*'))
=> SELECT * FROM "users"  WHERE "users"."age" > 10

users.where(users[:age].lteq(10)).project(Arel.sql('*'))
=> SELECT * FROM "users"  WHERE "users"."age" <= 10

users.where(users[:age].gteq(10)).project(Arel.sql('*'))
=> SELECT * FROM "users"  WHERE "users"."age" >= 10

users.where(users[:age].in([20, 16, 17])).project(Arel.sql('*'))
=> SELECT * FROM "users"  WHERE "users"."age" IN (20, 16, 17)
  • Bitwise operators &, |, ^, <<, >>:
users.where((users[:bitmap] & 16).gt(0)).project(Arel.sql('*'))
# => SELECT * FROM "users"  WHERE ("users"."bitmap" & 16) > 0

users.where((users[:bitmap] | 16).gt(0)).project(Arel.sql('*'))
# => SELECT * FROM "users"  WHERE ("users"."bitmap" | 16) > 0

users.where((users[:bitmap] ^ 16).gt(0)).project(Arel.sql('*'))
# => SELECT * FROM "users"  WHERE ("users"."bitmap" ^ 16) > 0

users.where((users[:bitmap] << 1).gt(0)).project(Arel.sql('*'))
# => SELECT * FROM "users"  WHERE ("users"."bitmap" << 1) > 0

users.where((users[:bitmap] >> 1).gt(0)).project(Arel.sql('*'))
# => SELECT * FROM "users"  WHERE ("users"."bitmap" >> 1) > 0

users.where((~ users[:bitmap]).gt(0)).project(Arel.sql('*'))
# => SELECT * FROM "users" WHERE  ~ "users"."bitmap" > 0
  1. Viết scope bằng arel
class User < ApplicationRecord
  has_many :payments

  has_secure_password
  
  scope :inactive_users, ->{where(valid_updated_at).or(valid_created_at)}

  class << self
    def valid_updated_at
      arel_table[:updated_at].lteq Time.now.utc
    end

    def valid_created_at
      arel_table[:created_at].gteq Time.now.utc
    end
  end
end