Ruby on Rails 使用 draper gem 實現 decorator design pattern
Ruby on Rails 使用 draper gem 實現 decorator design pattern 的一些用法以及一些筆記,方便某天忘記時可以回過頭來看。
在開發時常會碰到需要在 view 上撰寫 if else 邏輯的情況,我們可能會把邏輯判斷寫在 helper 內,這時可能會碰到 namespace 或是命名重複的問題,一方面又要保持 DRY 跟好維護,我會使用 draper 這個 gem 來實現 decorator design pattern。
範例
把檔案放在 app/decorators
下,命名前綴就依照 model 名稱,例如 project_decorator
。
安裝好 gem 之後,要 run 過
rails generate draper:install
建立 ApplicationDecorator
後續就可以用指令
rails generate decorator MODEL_NAME
快速的建立 Decorator
helper
要使用 helper 要記得加 include Draper::LazyHelpers
,不然就要用 h.
或是 helpers.
class ProjectDecorator < Draper::Decorator
include Draper::LazyHelpers
end
取用 model
要呼叫原本的 model 就可以使用 object
例如:
def url
object.url || object.organization.url
end
我自己都會用 delegate_all
來讓原本 model 的方法都可以被呼叫
class ProjectDecorator < Draper::Decorator
delegate_all
def project_status
if platform?
# ...
else
# ...
end
end
end
platform?
就是來自原本的 Project.platform?
實例化
實例化單一 object
@project = Project.first
@decorate = @project.decorate
# 同下面
@decorate = ProjectDecorator.new(@project)
@decorate = ProjectDecorator.decorate(@project)
一次實例化多個 object
@projects = ProjectDecorator.decorate_collection(Project.all)
# 如果是 ActiveRecord 的查詢條件,可以直接下
@projects = Project.all.decorate
實例化 Collection
我自己是想不太到有什麼情境是需要用到這個🤡
class ProjectsDecorator < Draper::CollectionDecorator
#...
end
搭配 Kaminari paginate helper
class PaginatingDecorator < Draper::CollectionDecorator
delegate :current_page, :total_pages, :limit_value, :entry_name, :total_count, :offset_value, :last_page?
end
測試
公司的專案是使用 RSpec
所以在 controller 測試內可以寫
assigns(:project).should be_decorated
# 同上
assigns(:project).should be_decorated_with ProjectDecorator