12/08/2018, 14:48

Sử dụng Arel để truy vấn dữ liệu trong Ruby on Rails

Như chúng ta đã biết Ruby on Rails nổi tiếng với thời gian phát triển một ứng dụng Web trong thời gian khá ngắn, để làm được điều đó framework này ngoài khối lượng Gem khổng lồ thì bản thân nó cũng tự cung cấp những công cụ tiện dụng, đơn giản giúp tận dụng tối đa sức mạnh của mình cũng như khắc ...

Như chúng ta đã biết Ruby on Rails nổi tiếng với thời gian phát triển một ứng dụng Web trong thời gian khá ngắn, để làm được điều đó framework này ngoài khối lượng Gem khổng lồ thì bản thân nó cũng tự cung cấp những công cụ tiện dụng, đơn giản giúp tận dụng tối đa sức mạnh của mình cũng như khắc phục những điểm yếu còn tồn đọng trong framwork.

Arel là công cụ quản lý truy vấn dữ liệu cho Ruby với những điểm mạnh:

  • Khiến cho việc truy vấn dữ liệu dễ ràng và minh bạch hơn.
  • Tương thích với nhiều loại DB.

Arel cung cấp những câu truy vấn đầy đủ, dễ sử dụng tận dụng tối đa thời gian để lập trình viên tập trung xây dựng những truy vấn phức tạp.

Chuẩn bị database với hai bảng

 #Student:
 create_table :students do |t|

      t.string :name
      t.integer :age
      t.references :class 
      t.timestamps
    end
  # Liên kết:
  belongs_to :room, class_name: Room, foreign_key: :class_id
  
  #Room
  create_table :rooms do |t|

      t.string :name
      t.timestamps
  end
  #Liên kết
  has_many :students, class_name: Student, foreign_key: :class_id

1. Khởi tạo liên kết giữa Arel và database model

 2.3.0-p0 :391 > students = Student.arel_table
 => #<Arel::Table:0x00000003e26c58 @name="students", @columns=nil, @type_caster=#<ActiveRecord::TypeCaster::Map:0x00000003e26ca8 @types=Student(id: integer, name: string, age: integer, class_id: integer, created_at: datetime, updated_at: datetime)>, @table_alias=nil>

Khởi tạo query từ liên kết trên

  2.3.0-p0 :126 > query = students.project(Arel.sql('*'))
   => #<Arel::SelectManager:0x00000002abb830 @ctx=#<Arel::Nodes::SelectCore:0x00000002abb7b8 @source=#<Arel::Nodes::JoinSource:0x00000002abb790 @left=#    <Arel::Table:0x00000002ae8308 @name="students", @columns=nil, @type_caster=nil, @table_alias=nil>, @right=[]>, @top=nil, @set_quantifier=nil, @projections=["*"], @wheres=[], @groups=[],   @havings=[], @windows=[]>, @bind_values=[], @ast=#<Arel::Nodes::SelectStatement:0x00000002abb7e0 @cores=[#<Arel::Nodes::SelectCore:0x00000002abb7b8 @source=#<Arel::Nodes::JoinSource:0x00000002abb790 @left=#<Arel::Table:0x00000002ae8308 @name="students", @columns=nil, @type_caster=nil, @table_alias=nil>, @right=[]>, @top=nil, @set_quantifier=nil, @projections=["*"], @wheres=[], @groups=[], @havings=[], @windows=[]>], @orders=[], @limit=nil, @lock=nil, @offset=nil, @with=nil>>

Câu truy vấn tương đương với SQL

  2.3.0-p0 :130 >   query.to_sql
  => "SELECT * FROM `students`"

2. Một số câu truy vấn cơ bản

  • Truy vấn với điều kiện where
  2.3.0-p0 :394 > Student.where(s[:name].eq("Student1"))
  Student Load (1.2ms)  SELECT `students`.* FROM `students` WHERE `students`.`name` = 'Student1'
  • Truy vấn với select
  2.3.0-p0 :408 >   Student.select(students[:id])
  Student Load (1.1ms)  SELECT `students`.`id` FROM `students`
  • Truy vấn với các toán tử so sánh =, !=, <, >, <=, >=, IN
Student.where(students[:age].eq(21))
# => SELECT * FROM "students"  WHERE "students"."age" = 10

Student.where(students[:age].not_eq(21)))
# => SELECT * FROM "students"  WHERE "students"."age" != 21

Student.where(students[:age].lt(21)))
# => SELECT * FROM "students"  WHERE "students"."age" < 21

Student.where(students[:age].gt(21)))
# => SELECT * FROM "students"  WHERE "students"."age" > 21

Student.where(students[:age].lteq(21)))
# => SELECT * FROM "students"  WHERE "students"."age" <= 21

Student.where(students[:age].gteq(21)))
# => SELECT * FROM "students"  WHERE "students"."age" >= 21

Student.where(students[:age].in([21, 22])))
# => SELECT * FROM "students"  WHERE "students"."age" IN (21, 22)
  • Truy vấn với &, |, ^, <<, >>
Student.where((students[:bitmap] & 21).gt(0)))
# => SELECT * FROM "students"  WHERE ("students"."bitmap" & 21) > 0

Student.where((students[:bitmap] | 21).gt(0)))
# => SELECT * FROM "students"  WHERE ("students"."bitmap" | 21) > 0

Student.where((students[:bitmap] ^ 21).gt(0)))
# => SELECT * FROM "students"  WHERE ("students"."bitmap" ^ 21) > 0

Student.where((students[:bitmap] << 1).gt(0)))
# => SELECT * FROM "students"  WHERE ("students"."bitmap" << 1) > 0

Student.where((students[:bitmap] >> 1).gt(0)))
# => SELECT * FROM "students"  WHERE ("students"."bitmap" >> 1) > 0

Student.where((~ students[:bitmap]).gt(0)))
# => SELECT * FROM "students" WHERE  ~ "students"."bitmap" > 0
  • Joins with Arel
2.3.0-p0 :552 > Student.joins(:room).on(students[:id].eq(rooms[:class_id])).to_sql
 => "SELECT `students`.* FROM `students` INNER JOIN `rooms` ON `students`.`id` = `rooms`.`class_id`" 
  • LIMIT và OFFSET
2.3.0-p0 :554 > students.take(5).to_sql
 => "SELECT  FROM `students` LIMIT 5"
 
2.3.0-p0 :555 > students.skip(5).to_sql
 => "SELECT FROM `students` LIMIT 18446744073709551615 OFFSET 5"

Có thể thấy viết query sử dụng Arel khá dễ dàng và minh bạch. Lập trình viên hoàn toàn có thể quên đi những câu SQL dài dòng và phức tạp, tận dụng thời gian để xây dựng những câu query lớn hơn. Để hiểu chi tiết hơn về Arel các bạn có thể tham khảo Tại đây.

Thanks for listening !!!

0