Active Record – Cây cầu nối tới Database của Rails
Mở đầu Đối với lập trình viên, một trong những kỹ năng quan trọng nhất là lập luận logic, chia vấn đề thành những phần nhỏ và giải quyết từng phần một. Khi bạn tạo ra một website, có lẽ phần quan trọng nhất trong lập luận logic mà bạn cần làm đó là thiết lập cấu trúc database cho trang web ...
Mở đầu
Đối với lập trình viên, một trong những kỹ năng quan trọng nhất là lập luận logic, chia vấn đề thành những phần nhỏ và giải quyết từng phần một. Khi bạn tạo ra một website, có lẽ phần quan trọng nhất trong lập luận logic mà bạn cần làm đó là thiết lập cấu trúc database cho trang web đó. Data là phần không thể thiếu đối với hầu hết các ứng dụng web, từ một trang blog đơn giản cho tới một Facebook với lượng data khổng lồ và cực kỳ phức tạp. Một database được thiết kế không đúng cách, quá rối rắm hoặc phức tạp sẽ khiến cho việc lập trình của bạn trở nên đau đớn, ngăn chặn việc mở rộng service của bạn. Khi bạn sử dụng sai công cụ hỗ trợ phát triển, thì ngay cả những việc đơn giản như hiển thị một nội dung vừa được đăng, cũng gây hao tốn quá nhiều công sức suy nghĩ cũng như tài nguyên CPU để hoàn thành.
Nếu data là mảnh ghép tối quan trọng trong ứng dụng web của bạn, thì cách mà Rails thao tác với data có thể sẽ làm bạn cảm thấy thú vị. Đây chính là một trong những lí do chính khiến cho Rails hoạt động tốt khi so sánh với những lựa chọn khác trong một vài năm trở lại đây. Rails cung cấp Active Record - một ORM nằm giữa database và ứng dụng web. Nó cho phép bạn cấu trúc các model dữ liệu như user, blog, post, comment theo một cách rất logic và gần với tiếng Anh. Có được một hiểu biết vững chắc về Active Record, bạn sẽ cảm thấy Rails trở nên tương đối đơn giản và dễ nắm bắt. Active Record là một ORM, vậy bạn có biết ORM là gì?
ORM là gì
Trong quá khứ, để xây dựng một ứng dụng web, lập trình viên cần phải có cả kĩ năng viết code ở cả business language và database language. Làm việc với các database language không phải là điều dễ chịu đối với các coder, đặc biệt là khi bạn phải đối mặt với việc thao tác dữ liệu trên nhiều table khác nhau kết hợp cùng các data-filter. Và ORM ra đời như một cứu cánh cho dân lập trình.
ORM là viết tắt của cụm từ Object Relational Mapping là một kĩ năng trong lập trình giúp chuyển đổi dữ liệu giữa các hệ thống không tương thích trong lập trình hướng đối tượng. Nó tạo ra một Cơ sở dữ liệu object ảo, có thể sử dụng được bên trong ngôn ngữ lập trình.
Nói cách khác, một ORM framework là một layer nằm ở giữa ngôn ngữ lập trình và database, được viết bằng một ngôn ngữ lập trình hướng đối tượng (như là Ruby, Python, PHP ...) giúp bạn có thể sử dụng chính ngôn ngữ lập trình đó để thao tác với database mà không cần viết các câu lệnh SQL dài dòng. Các object class sẽ tương ứng với các bảng dữ liệu trong database, và các object instance sẽ tương ứng với các record trong các bảng dữ liệu đó.
Điểm mạnh
ORM mang đến nhiều tiện ích cho lập trình viên. Có thể kể ra như sau:
-
Độc lập với Database Đây có lẽ là lợi ích lớn nhất khi sử dụng ORM trong một ứng dụng. Bạn không cần viết các câu lệnh của database. Bạn đang sử dụng SQLite, bạn không thích và đổi sang MySQL hay PostgreSQL, lúc này bạn cũng k cần phải sửa các câu lệnh bởi ORM đã làm hết cho bạn. Kể cả khi thay đổi database, bạn cũng chỉ cần chỉnh sửa một vài dòng trong Database configuration adapter.
-
Giảm số lượng dòng code và tăng hiệu quả lập trình ORM cho phép lập trình viên có thể tập trung vào các business logic hơn là viết các câu query phức tạp tới database, nhờ đó thu gọn được code và tăng hiệu quả làm việc.
-
Query Interface đa dạng ORM framework mang đến một số lượng query interface đa dạng, giải quyết được hầu hết các trường hợp có thể xảy ra tương ứng với những câu lệnh SQL phức tạp.
-
Quan hệ giữa các dữ liệu ORM giúp quản lý hiệu quả mối liên hệ giữa các dữ liệu. Các object liên quan đều được load một cách tự động khi một query được dịch sang câu lệnh SQL tương ứng.
-
Xử lý đồng thời ORM hỗ trợ xử lý đồng thời, cho phép nhiều user có thể update một tập hợp các data cùng một lúc.
-
Caching Object được cache lại, giảm thiểu thời gian load trên database.
-
Transaction Nhiều sự thay đổi của object đều có thể đưa vào chung trong 1 transaction, nhờ đó chúng có thể đồng thời được thực thi (commit) cũng như bị huỷ bỏ (rollback). Nhiều transaction có thể chạy cùng một lúc nhưng mỗi transaction đều độc lập với các transaction khác.
ORM mang đến nhiều tiện ích cho lập trình viên. Có thể kể ra như sau:
Điểm yếu
-
Tăng xử lý ORM framework tạo ra một layer giữa ngôn ngữ lập trình và database, giúp giảm sự phức tạp trong lập trình và tăng tốc độ phát triển. Tuy nhiên điều này cũng làm tăng thêm các xử lý trong ứng dụng. Sử dụng ORM sẽ tiêu tốn nhiều dữ liệu và tài nguyên CPU hơn.
-
Làm quen Để đưa một ORM vào trong ứng dụng, các lập trình viên sẽ cần thêm kĩ năng để sử dụng một framework mới. Do đó sẽ mất thời gian để làm quen.
-
Hiệu suất Một số thao tác như insert hàng loạt, sửa xoá ... sẽ chậm hơn khi được viết bằng ORM. Thông thường, các công việc này sẽ có hiệu năng cao hơn nếu sử dụng trực tiếp câu lệnh SQL thuần.
-
Bỏ quên SQL Sử dụng ORM giúp lập trình viên dễ dàng hơn trong thao tác với database nhưng cũng dẫn tới việc lập trình viên không nghiên cứu chi tiết vào SQL, tạo ra lỗ hổng kiến thức.
Giới thiệu về Active Record
Bạn đã biết ORM là gì, chúng ta hãy tìm hiểu tiếp về Active Record. Phần sau đây sẽ giới thiệu một cách đơn giản về các tính năng cũng như cách sử dụng của Active Record.
Bạn có biết Rails thực chất là tổng hợp của 7 gem Ruby hoạt động cùng nhau. Trong đó, Active Record chính là gem đóng vai trò của một ORM, có nhiệm vụ xử lý các thao tác liên quan tới database. Active Record lấy những data được lưu trữ trong các bảng của database sử dụng các row và column. Việc truy xuất hoặc sửa đổi các data này vốn được thực hiện bởi các câu lệnh SQL (nếu bạn sử dụng SQL database), nay đã được đơn giản hoá thành việc thao tác với các Ruby object thông thường.
Nếu bạn muốn lấy một mảng bao gồm tất cả user, thay vì phải viết code để khởi tạo liên kết tới database và viết các query như SELECT * FROM users, rồi convert kết quả đó sang dạng mảng, bạn chỉ cần viết User.all và Active Record sẽ lấy về cho bạn một mảng bao gồm tất cả các user của bạn. Thật tuyệt phải không.
Ấn tượng hơn nữa, bạn không cần phải quan tâm nhiều tới việc mình sử dụng database gì (nếu bạn thiết lập chuẩn xác trong file config/database.yml), Active Record đã lo cho bạn việc đồng nhất xử lý đối với các database khác nhau. Bạn chỉ cần tập trung viết code cho ứng dụng của mình. Điều này cũng đồng nghĩa với việc, khi bạn sửa đổi database, bạn không cần thiết phải chỉnh sửa nhiều code trong ứng dụng mà chỉ là vài dòng trong file thiết lập.
Rails Model
Active Record giao tiếp với database, nó đóng vai trò là phần M trong MVC của Rails: models. Model là nơi xử lý hầu hết các business logic trong ứng dụng của bạn. Bạn muốn lưu giữ thông tin về các users của mình, bạn tạo một bảng trong database đặt tên là users. Bạn muốn truy nhập vào bảng đó từ trong ứng dụng của bạn, bạn tạo một model đặt tên là User. Một bảng trong database sẽ tương ứng với một model được thừa kế từ Active Record. Chỉ thế thôi, bạn đã có thể sử dụng các phương thức vô cùng tiện lợi như all, find và create ...
Sau khi khởi tạo một project Rails sử dụng các câu lệnh:
rails new myapp cd myapp
và tạo ra database: rake db:create
Bạn có thể tạo ra model như sau (cả 3 kiểu ở dưới đây đều có thể hoạt động):
rails generate model User rails g model User rails g model User name:string age:integer
Hai câu lệnh đầu tiên làm cùng một việc, ở đây rails g chỉ là một shortcut của rails generate. Câu lệnh thứ ba sẽ tạo thêm một số thông tin, đó là thêm vào hai trường name (kiểu string) và age (kiểu integer) cho model User. Bên cạnh đó, sẽ có thêm 2 file được tạo ra, dạng như sau
create db/migrate/20130213204626_create_users.rb create app/models/user.rb
File đầu tiên, là một file migrate, sử dụng để sửa database. Ta sẽ nói tới migration sau. File thứ hai, chính là một class của Ruby, class này kế thừa từ Active Record.
Đến đây, sau khi thực hiện migration, bạn sẽ có thể sử dụng các câu lệnh của Active Record đối với model user.
Tạo ra một record user thật đơn giản. Bạn chỉ cần gọi method create của class User và truyền vào đó tham số là một Hash bao gồm các key và value là các trường của model User và các giá trị tương ứng.
User.create(name: “Cuong”, age: 69)
Việc update các giá trị của model cũng rất dễ dàng với instance method: update_attributes…
Ta sẽ không đi sâu vào việc tìm hiểu từng method của Active Record bởi bạn hoàn toàn có thể tìm được trong các document trên internet. Phần tiếp theo, hãy tìm hiểu xem migration là gì.
Migration
Bạn cần migration khi nào? Đó là khi bạn cần những sự thay đổi về cấu trúc database. Bạn sẽ định nghĩa những thay đổi đó sử dụng các câu lệnh của Rails, các file migration sẽ được tạo ra và bạn chạy
rake db:migrate
để cập nhật các thay đổi này vào database.
Cấu trúc một file migration có thể như sau:
class CreateUsers < ActiveRecord::Migration def change create_table :users do |t| t.string :name t.integer :age t.timestamps end end end
Bạn cũng có thể đảo ngược quá trình thay đổi database mà bạn vừa tạo ra với câu lệnh:
rake db:rollback
Validations
Validation là một phần quan trọng của mọi ứng dụng Web. Đây là nơi ta đưa ra các điều kiện để chắc chắn rằng những dữ liệu được đưa vào trong database là chính xác và đúng chuẩn.
Phải nói thêm rằng, các luật validation được tạo ra trong model của bạn không được thực hiện ở cấp độ database mà nó chỉ được đưa vào trong các xử lý của Rails.
Trong version hiện tại của Rails, chúng ta sử dụng method validates để thiết lập tất cả các validation. Tham số của method này bao gồm các trường của model và các thuộc tính validation.
Rails hỗ trợ rất nhiều kiểu validation, như là presence, uniqueness, inclusion, exclusion, length ...
Một ví dụ của validation:
validates :age, presence: true
Callback
Callback lại là một phần thú vị khác của Active Record. Nó cho phép chúng ta chạy các method tại một thời điểm được định trước.
Đầu tiên, ta tạo ra một method muốn sử dụng trong callback:
def set_name self.name = “Cuong” end
sau đó ta đăng ký callback:
before_save :set_name
Điều này có nghĩa là , cứ mỗi khi ta gọi lệnh save, method set_name sẽ được chạy xong trước khi save được hoàn thành.
Có các loại validation như sau:
- before_validation / after_validation
- before_save / around_save / after_save
- before_create / around_create / after_create
- before_update / around_update / after_update
- before_destroy / around_destroy / after_destroy
Associations
Hầu hết các relational database đều có nhiều các bảng có mối liên hệt với nhau. Tất nhiên Active Record có cơ chế để thiết lập các liên kết đó.
Ví dụ như: ngoài model User, chúng ta còn có thêm một model là Account , và một user có thể có nhiều account. Làm thế nào ta có thể tạo được liên kết này.
Đầu tiên hãy tạo ra model account
rails g model Account balance:integer, user_id:integer
Ở đây trường user_id chính là foreign key ta sử dụng để liên kết giữa hai model.
Sau khi chạy migration rake db:migrate , ta đã có thể thông báo cho các class về mối liên hệ giữa hai model.
Trong class app/model/user.rb thêm dòng sau:
has_many :accounts
Trong class app/model/account.rb
belongs_to :user
Như vậy, trong model User ta định nghĩa rằng một user có thể có nhiều account, và ngược lại mỗi account đều thuộc về user.
Chúng ta có thể kiểm tra mối quan hệ này như sau.
u = User.create id: 1, name: “Haha”, age: 69 acc = Acc.new balance: 96 acc.user = u a.save user.accounts
Kết quả sẽ có dạng như sau
#=> [#<Account id: 1 ... >]
Lời kết
Active Record là tính năng mạnh nhất của Rails và cũng là một trong những phần khó hiểu nhất để bạn có thể làm quen với Rails. Khái niệm khó nhất của ActiveRecord có lẽ là Association. Hi vọng thông qua bài giới thiệu đơn giản này, bạn có thể nắm được các khái niệm cơ bản của Active Record. Chúc bạn nhanh chóng làm quen với Active Record và sớm tạo ra được trang web của riêng mình.