Gem Draper
Bài đăng này đã không được cập nhật trong 5 năm
1. Why use a Decorator:
- Tưởng tượng bạn có
Articlemodel. - Với gem
Draperbạn có thể tạo 1 classArticleDecorator. - Class này gói model
Articleở bên trong, định nghĩa các hàm xử lý logic của modelArticle.# app/decorators/application_decorator.rb class ApplicationDecorator < Draper::Decorator delegate_all end # app/decorators/article_decorator.rb class ArticleDecorator < ApplicationDecorator def publication_status return "Drafting" if drafting? "Published at #{published_at.strftime("%A, %B %e")}" end end - Thực hiện tạo decorator ở controller trước khi sử dụng trong view như sau.
# app/controllers/articles_controller.rb def show @article = Article.find(params[:id]).decorate end - Ở view, bạn có thể sử dụng
@articleđã được decorate như sử dụng model và có thể gọi các method decorator.# app/views/articles/show.html.erb <%= article.id %> <%= article.title %> <%= article.content %> <%= article.publication_status %> - Bạn cũng có thể tạo article_helper và implement phương thức
publication_statusnhư sau.# app/helpers/article_helper.rb module ArticleHelper def publication_status article return "Drafting" if article.drafting? "Published at #{article.published_at.strftime("%A, %B %e")}" end end - Tuy nhiên cách này có 1 số hạn chế sau
- Phương thức
publication_statussẽ tồn tại ở tất cả view và controller, không chỉ trongArticleController - Giả sử bạn có thêm model
Bookvà bạn cần implement phương thứcpublication_statuscho book - Bạn cần phải sửa code ở phương thức
publication_statusnhư sau# app/helpers/article_helper.rb module ArticleHelper def publication_status object case object.class when Article # implement publication_status for Article when Book # implement publication_status for Book end end end - Các này bạn phải sửa code ở trong helper đã viết, bên cạnh đó
ArticleHelperlại đang implement logic củaBook. - Hoặc chia thành cách method
publication_status_article,publication_status_book - Trong khi với gem
Decorator, bạn chỉ cần tạoBookDecoratorvà implementpublication_status# app/helpers/book_helper.rb class BookDecorator < Draper::Decorator def publication_status return "Drafting" if drafting? "Published at #{published_at.strftime("%A, %B %e")}" end end - Cách này không cần sửa code cũ và vẫn đảm bảo các model không chồng chéo nhau.
- Với cách tiếp cận implement
publication_statustrong từng model thì dễ dẫn đến fat model. - Các method trong model chỉ nên chứa các hàm logic liên quan đến việc CRUD của model đó.
- Các method sau nên đưa vào decorator
- Các method hiển thị attribute của model
- Các method để tính toán dữ liệu giữa các attribute của model, ví dụ tính toán
nametừfirst_namevàlast_name, tính toánagetừbirthday. - Các method để tính toán url của model, ví dụ tính toán user đã cập nhật đủ thông tin thì trả về
user_path, ngược lại trả vềedit_user_path.
2. Installation:
- Thêm gem
Drapervào Gemfile.# Gemfile gem "draper" - Chạy
bundle installđể install gemDrapervào source code.
3. Writing Decorators:
- Bạn có thể tạo decorator kế thừa trực tiếp từ
Draper::Decoratornhư sau# app/decorators/article_decorator.rb class ArticleDecorator < Draper::Decorator end - Hoặc tạo
ApplicationDecoratorkế thừaDraper::Decoratorvà cho decorator kế thừaApplicationDecoratornhư sau# app/decorators/application_decorator.rb class ApplicationDecorator < Draper::Decorator end # app/decorators/article_decorator.rb class ArticleDecorator < ApplicationDecorator end
4. Generators:
- Để tạo
ApplicationDecoratorta chạyrails generate draper:install - Để tạo
ArticleDecoratorta chạyrails generate decorator Article - Để tạo
ArticleDecoratorcùng với các file khác như migration, model, helper, .... ta chạyrails generate resource Article
5. Accessing Helpers:
- Để sử dụng các method của helper trong decorator ra sử dụng method
h. - Ta cần
include Draper::LazyHelpersđể tránh bị chậm khi gọi methodhthường xuyên# app/decorators/article_decorator.rb class ArticleDecorator < ApplicationDecorator include Draper::LazyHelpers def emphatic h.content_tag(:strong, "Awesome") end end
6. Accessing the model:
- Để sử dụng các method của model trong decorator, ví dụ method
published?, ta có thể sử dụng 1 trong các cách gọi sauself.object.published? object.published? model.published? published? - Trong đó
selflàdecorator,objecthaymodellà record đang được gói lại bởidecorator.
7. Decorating Objects:
a. Single object:
- Để tạo decorator trên 1 object, ta gọi method
decorate.@article = Article.first.decorate - Theo mặc định, gọi method
decoratesẽ trả về decorate ứng với model đó, ví dụ trên sẽ trả vềArticleDecorator. - Nếu muốn trả về BookDecorator với article object ta có thể làm như sau.
@article = BookDecorator.new(Article.first) @article = BookDecorator.decorate(Article.first)
b. Collections:
- Tương tự, chúng ta có thể trả về decorator cho collection theo 2 cách sau.
@articleas = Article.all.decorate @article = ArticleDecorator.decorate_collection(Article.all)
c. Using pagination:
- 1 vài gem dùng để pagination thêm 1 số method vào
ActiveRecord::Relation. - Ví dụ method
paginatecủa gemkaminarithêm 1 số method sau vàoActiveRecord::Relation:current_page,total_pages,limit_value, .... - Để gọi các method trên với decorator, ta thực hiện delegate
# app/decorators/paginating_decorator.rb class PaginatingDecorator < Draper::CollectionDecorator delegate :current_page, :total_pages, :limit_value, :entry_name, :total_count, :offset_value, :last_page? end # app/decorators/article_decorator.rb class ArticleDecorator < ApplicationDecorator def self.collection_decorator_class PaginatingDecorator end end - Thực hiện paginate cho collection paginate như collection bình thường
@articles = Article.page(0).decorate @articles = ArticleDecorator.decorate_collection(Article.page(0)) @articles.total_pages
8. Document
- Thanks to drapper
- Source code tham khảo: https://github.com/thanhlt-1007/demo_draper
All rights reserved