Sử dụng Arel để truy vấn dữ liệu trong Ruby on Rails
Bài đăng này đã không được cập nhật trong 7 năm
GIỚI THIỆU
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.
CÁCH SỬ DỤNG VÀ NHỮNG CÂU TRUY VẤN ĐƠN GIẢN
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"
KẾT LUẬN
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 !!!
All rights reserved