+7

Tìm hiểu Decorator trong Rails

1. Decorator là gì?

Như chúng ta đã biết, RoR được xây dựng trên mô hình MVC. Trong đó Model đóng vai trò xử lý dữ liệu, Views có nhiện vụ hiển thị dữ liệu cho người dùng.

Giả sử bạn đang xây dựng một hệ thống tuyển dụng nhân sự, trong đó cần lưu rất nhiều thông tin của các ứng viên (Candidate). Để phục vụ cho việc filter, hệ thống cần lưu tên của từng ứng viên dưới dạng first_namelast_name. Nhưng trên views bạn cần hiện thị tên ứng viên đó dưới dạng full_name = first_name + last_name. Đối với trường hợp, cách nhanh nhất chúng ta nghĩ đến là sẽ xây dựng một hàm full_name trong model Candidate.

Tuy nhiên đối với những hệ thống lớn, số lượng phương thức cần xử lý tương tự như vậy sẽ rất lớn. Chính vì vậy khi cần nâng cấp, bảo trì hệ thống sẽ rất khó khăn. Decorator được sinh ra để giải quyết vấn đề này. Nó là cầu nối giữa Model và View.

Decorator như một lớp con, cho phép chúng ta tạo thêm những hành động cho đối tượng mà không gây ảnh hưởng tới những đối tượng khác của cùng một lớp. Trong trường hợp trên thì phương thức full_name chỉ tác động lên một đối tượng @candidate thuộc lớp Candidate.

2. Ví dụ về Decorator

Có nhiều cách để sử dụng decorator trong một project. Bạn có thể tự cài đặt thủ công hoặc dùng các gem hỗ trợ như ActiveDecorator hoặc Draper.

Chúng ta sẽ bắt đầu với gem Draper

Trước tiên chúng ta thêm gem vào Gemfile

gem "draper"

Sau đó cài đặt và khởi tạo một lớp decorator cho model Candidate

$ bundle install
$ rails generate decorator Candidate

Tất cả code decorator của mọi model sẽ được lưu trữ trong folder app/decorators/. Lệnh khởi tạo bên trên sẽ sinh ra một file app/decorators/candidate_decorator.rb có nội dung như sau:

class CandidateDecorator < Draper::Decorator
    delegate_all
end

Giờ chúng ta chỉ cần viết thêm các phương thức trong đó.

class CandidateDecorator < Draper::Decorator
    delegate_all

    def full_name
        if first_name.blank? && last_name.blank?
            "No name is provided"
        else
            "#{first_name} #{last_name}"
        end
    end

    def link_to_candidate
       link_to candidate.full_name, candidate
    end
end

Sau khi đã hoàn thiện phương thức trong decorate bạn chỉ cần gọi .decorate trong bất kỳ đối tượng ActiveRecord nào của dự án.

class CandidatesController < ApplicationController
    def index
       @candidates = Candidate.all.decorate
    end

    def show
       @candidate = Candidate.find(params[:id]).decorate
    end
end

Trên views chúng ta gọi ra như sau:

<p id="candidate-<% @candidate.id %>"> Candidate information </p>
<p>
    <strong>Full name:</strong>
    <%= @candidate.link_to_candidate %>
</p>

Draper khá dễ hiểu và sử dụng. Các bạn có thể tham khảo thêm tại: Draper

Tiếp theo chúng ta sẽ cùng thực hiện cài đặt decorator theo cách hoàn toàn thủ công. Đầu tiên chúng ta tạo thư mục decorators trong thư mục dự án:

$ mkdir app/decorators

Tạo file decorator của model Candidate tại app/decorators/candidate_decorator.rb

module CandidateDecorator def full_name "#{first_name} #{last_name}" end end

Việc còn lại là làm sao để một đối tượng @candidate của lớp Candidate có thể sử dụng phương thức full_name chúng ta vừa tạo. Chúng ta chỉ cần include module CandidateDecorator vào lớp Candidate.

class Candidate < ActiveRecord::Base
    include CandidateDecorator
end

Giờ thì trên views chúng ta hoàn toàn sử dụng các phương thức trong decorator Candidate như bình thường cho mọi đối tượng của Candidate.

3. Kết luận

Decorator pattern là một design pattern được thiết kế giúp việc quản lý tốt hơn các phương thức hỗ trợ đối với một đối tượng độc lập mà không ảnh hưởng tới những đối tượng tác cùng lớp. Nó cũng giúp giảm số lượng dòng code trong Model, đóng vai trò giống như model và có thể giao tiếp với views. Với những hệ thống nhỏ thì không thực sự cần thiết để dùng decorator mà chúng ta hoàn toàn có thể viết các phương thức đó ngay trong model. Tuy nhiên nó tỏ ra rất hiệu quả đối với những hệ thống lớn.

Để tìm hiểu nhiều hơn về decorator bạn có thể tham khảo các link sau:

http://johnotander.com/rails/2014/03/07/decorators-on-rails

https://github.com/amatsuda/active_decorator

https://github.com/drapergem/draper

Cám ơn các bạn rất nhiều!


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí