MVC Trong Rails (Phần 2)
Bài đăng này đã không được cập nhật trong 3 năm
Mô hình MVC được Trygve Reenskaug đề ra vào năm 1979, mô hình này chia ứng dụng làm 3 phần: model, view và controller. Là mô hình giúp ta có thể sử dụng lại code đã viết.
Trong đó model sẽ chịu trách nhiệm duy trì dữ liệu của ứng dụng. Đôi khi dữ liệu này chỉ tồn tại trong một thời gian ngắn, đôi khi lại được lưu trữ lâu dài trong cơ sở dữ liệu. Ở đây model không đơn thuần chỉ là dữ liệu, ứng dụng sẽ buộc phải chạy theo các quy tắc đã áp đặt lên dữ liệu đó.
View sẽ chịu trách nhiệm tạo ra giao diện người dùng, và giao diện này sẽ dựa trên model.View sẽ lấy dữ liệu từ model và chuyển đổi thành giao diện hiển thị lên cho người dùng. Công việc của view là chỉ có hiển thị chứ không xử lý bất kỳ thao tác nào của người dùng. Một model có thể được truy cập bởi nhiều view.
Controller sẽ chịu trách nhiệm vận hành ứng dụng. Controller sẽ nhận các sự kiện từ bên ngoài, thông thường là từ người dùng, sau đó tương tác với model và gọi view tương ứng để hiển thị.
Bộ ba Model, Controller và View hợp thành thành mô hình MVC. Mô hình MVC cho phép chúng ta tách ứng dụng thành các bộ phận riêng biệt, nhờ đó chúng ta có thể dễ dàng phát triển và bảo trì ứng dụng. Ruby on Rails cũng được phát triển theo mô hình MVC.
Bất cứ ứng dụng Rails nào cũng có 3 phần model, view và controller. Việc kết nối giữa 3 thành phần này đã được Rails giải quyết tự động rồi, do đó bạn chỉ cần quan tâm đến việc phát triển từng thành phần thôi.
Trong một ứng dụng Rails, một gói tin HTTP được gửi từ trình duyệt sẽ được chuyển tới các router trước tiên, đây là nơi vận chuyển các gói tin HTTP đến các phương thức nhất định (trong Rails thì phương thức hay hàm còn có tên khác là action). Phương thức đó sẽ đọc các dữ liệu có trong gói tin và có thể sẽ tương tác với model, hoặc gọi thêm các phương thức/action khác. Cuối cùng thì phương thức đầu tiên được gọi đó sẽ tính toán ra các dữ liệu khác rồi gửi cho một view nào đó để hiển thị cho người dùng.
Tính năng Object Relational Mapping
Chính vì vậy mà nhóm phát triển đã cho ra đời một tính năng hỗ trợ việc chuyển đối dữ liệu quan hệ sang các đối tượng một cách dễ dàng đó là tính năng Object Relational Mapping (ORM)
Các thư viện ORM sẽ làm công việc chuyển đổi các bảng trong CSDL sang các lớp. Ví dụ như trong CSDL có bảng Order (đơn hàng) thì ORM sẽ tạo một lớp có tên Order trong Ruby, các dòng trong bảng sẽ là các đối tượng của lớp đó, các thuộc tính của lớp sẽ tương ứng với các cột trong bảng. Ngoài ra ORM sẽ định nghĩa các phương thức để chúng ta có thể đọc ghi dữ liệu một cách dễ dàng. Ví dụ chúng ta sẽ có các đoạn code dạng như sau:
order = Order.find(1)
...
Order.where(:name => 'market').each do |order|
order.payment = "Paypal"
order.save
end
Active Record
Tầng logic nằm giữa các nhu cầu xử lý dữ liệu của lập trình viên và các lệnh cấp thấp tương tác trực tiếp với database engine (như MySQL hoặc PostgreSQL).
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.
Về cơ bản, các SQL database đều quy định khá chặt chẽ về cấu trúc các bảng dữ liệu, được gọi là schema. Mỗi khi chúng ta định nghĩa 1 bảng dữ liệu, 1 schema được sinh ra để lưu lại cấu trúc của bảng đó. Tuy nhiên trong quá trình phát triển dự án, schema cần luôn luôn thay đổi 1 cách linh hoạt. Nếu chỉ tiến hành thay đổi tại Active Record, các database engine sẽ báo lỗi do sự sai khác về định nghĩa. Lúc này có 2 cách để tiếp tục làm việc:
Drop database: tức là xóa toàn bộ dữ liệu của bảng đó đi, khi đó database engine sẽ ghi dữ liệu theo schema mới
Viết các Migration: toàn bộ dữ liệu vẫn được dữ nguyên, nhưng database engine biết được cột (column) nào sẽ được thay đổi và cần thay đổi như thế nào.
Action Pack
Như chúng ta đã biết, controller sẽ gửi dữ liệu cho view, nhận và xử lý sự kiện từ view, do đó view và controller khá “thân thiết” với nhau. Chính vì vậy mà bộ phận xử lý controller và view được gộp lại làm một và được gọi là Action Pack. Bạn đừng hiểu lầm là chúng ta sẽ viết code cho view và controller chung một chỗ, ở đây chẳng qua chỉ là chúng được vận hành bởi cùng một thứ mà thôi. View
Trong Rails thì view có nhiệm vụ tạo ra các đoạn code HTML để hiển thị lên trình duyệt của người dùng, thông thường code HTML này có kèm theo dữ liệu được tạo ra từ các phương thức trong controller.
Các dữ liệu được tạo ra sẽ được tạo ra từ các template, bạn cứ hình dung đây giống như là một trình thông dịch nhỏ khác là được. Hiện có 3 loại template trong Rails là Embedded Ruby (ERb), XML Builder và RJS.
Trong đó ERb là phổ biến nhất, code ERb sẽ được nhúng chung với code HTML, nếu bạn đã từng làm việc với PHP hay JSP (Java) thì bạn sẽ thấy quen thuộc. Mặc dù code kiểu này rất linh hoạt nhưng đa phần người ta nghĩ rằng việc trộn chung công việc giữa các thành phần khác nhau là không nên. Controller
Phần controller trong Rails là bộ phận trung tâm, có nhiệm vụ xử lý tương tác giữa người dùng, view và model. Tuy nhiên chúng ta sẽ chỉ tập trung vào việc phát triển các tính năng của website, còn việc kết nối giữa các thành phần này sẽ được Rails giải quyết, chúng ta không cần quan tâm.
Cơ bản thì controller hỗ trợ các tính năng sau:
Định tuyến (routing) các URL tới các phương thức/hàm/action tương ứng. Ngoài ra controller còn định nghĩa các URL có cấu trúc thân thiện, dễ nhìn
+> Quản lý cache, giúp tăng hiệu năng của hệ thống
+> Quản lý các module hỗ trợ, giúp mở rộng các tính năng của template
+> Quản lý session, giúp theo dõi các hoạt động đang diễn ra trên ứng dụng
All rights reserved