Sử dụng gem Cells hiệu quả trong Ruby on Rails
Bài đăng này đã không được cập nhật trong 9 năm
Từ khi Rails ra đời cho tới nay các nhà phát triển rất chú trọng đến việc xây dựng các ứng dụng theo mô hình OOP, vừa để hướng theo những tư duy Code tiến bộ và cũng giảm bớt ghánh nặng cho các lập trình viên.
Trong mô hình MVC của Rails, mối quan hệ View - Models là rất quan trọng và có thể xây dựng nó theo OOP để việc tái sử dụng các hàm logic phức tạp trở lên dễ dàng, đồng thời giảm nhẹ và tối ưu code cho Models trong các dự án lớn.
Method “partial” có lẽ đã trở lên rất quen thuộc đối với mỗi lập trình viên Ruby on Rails, ưu điểm của nó là có thể gộp và tái sử dụng code View nhiều lần, tuy nhiên khi cần phải thao tác với nhiều hàm logic và muốn gộp chúng lại thành một Package để sử dụng thì vấn đề trở lên rất phức tạp và không khả thi.
Cells là một lựa chọn tuyệt vời cho bạn để giải quyết vấn đề này.
Ở bài viết này chúng ta cùng tìm hiểu và sử dụng gem Cells, đồng thời so sánh một vài thay đổi khi Cells 3.x được cập nhật lên phiên bản mới Cells 4.x
I - Cells là gì?
Cells là 1 gem được sử dụng để gộp cả view lẫn controller lại thành 1 package, phát huy tối đa tính đóng gói, kế thừa, kiểm thử, đặc biệt với những view có logic phức tạp, thì cells sẽ giúp code trở nên dễ đọc và dễ dàng tái sử dụng hơn.
**II - Khi nào nên sử dụng Cells? **
- xử lý các logic phức tạp, tái sử dụng lại code trong View - Models
- hiển thị popup login
- hiển thị ranking ở side menu
- hiển thị comment
- ...
III - Cài đặt gem Cells vào ứng dụng Rails
Thêm vào Gemfile trong ứng dụng của bạn :
gem 'cells'
Để sử dụng bạn cần thông qua generate :
rails generate cell popup_login show -e haml
Gọi một package trong Cells :
= render_cell :popup_login, :show, :property => @property_name
IV - Ví dụ với Popup Login
Khi sử dụng partial :
header_sign_in.html.haml
- unless user_signed_in?
.header
.header__login-button
= link_to 'login', 'javascript:void(0);'
= render partial: 'popup_login'
_popup_login.html.haml
- unless user_signed_in?
.popup-login
= form_for(@user, url:user_session_path) do |f|
%dl
%dt= f.label :email
%dd= f.email_field :email
%dt= f.label :password
%dd= f.password_field :password
= f.submit 'Login'
:javascript
$('.header__login-button a').click(function(){
$('.popup-login').css({ 'display' : 'block'});
});
Sẽ có lỗi xảy ra nếu object @user dùng trong file _popup_login.html.haml chưa được định nghĩa trong controller.
Ta có thể định nghĩa @user trong tất cả các action có gọi _popup_login, tuy nhiên một giải pháp tốt hơn là định nghĩa trong application_controller.
application_controller.rb
class ApplicationController < ActionController::Base
before_action: :pre_load
def pre_load
@user = User.new unless current_user.present?
end
end
Nhưng nếu logi phức tạp hơn như comment, ranking...thì chắc chắn code không chỉ đơn giản và ngắn gọn như vậy.
Giải pháp triệt để cho vấn đề này là ta dùng Cells :
Cấu trúc thư mục Cells sẽ như sau :
/app
/assets
/cells
/popup_login
show.html.haml
popup_login_cell.rb
Cụ thể, chức năng popup_login sẽ được viết như sau :
app/cells/popup_login_cells.rb
class PopupLoginCell < Cell::Rails
def show
@user = User.new unless current_user.present?
render
end
end
app/cells/popup_login/show.html.haml
- unless user_signed_in?
.popup-login
= form_for(@user, url:user_session_path) do |f|
%dl
%dt= f.label :email
%dd= f.email_field :email
%dt= f.label :password
%dd= f.password_field :password
= f.submit 'Login'
:javascript
$('.header__login-button a').click(function(){
$('.popup-login').css({ 'display' : 'block'});
});
Khi partial show được gọi, cells sẽ tự động gọi controller show tương ứng và thực hiện các login cần thiết.
Với cách làm này, những hàm logic sẽ chỉ được thực hiện khi gọi cells (tối ưu hơn hẳn khi dùng application_controller), và ta chỉ cần quan tâm đến việc gọi partial trong view là đủ.
V - So sánh phiên bản Cells 3.x với Cells 4.x
Khi phiên bản Cells 4.0 ra đời với tiêu chí : “Goodbye Rails! Hello Ruby!” đã hứa hẹn mang lại nhiều tiện ích mới cho các nhà phát triển ứng dụng.
Tuy nhiên trong phiên bản mới này Cells đã bỏ việc include các tính năng của ActiveView nhằm cải thiện tốc độ hiển thị. Để sử dụng các tính năng này bạn cần include thêm vào ứng dụng của mình :
cells/application.rb
class ApplicationCell < Cell::ViewModel
# helper tự định nghĩa
include ApplicationHelper
# helper của devise
include DeviseHelper
# helper của các gem
include FontAwesome::Rails::IconHelper
include BreadcrumbsOnRails::ControllerMixin::HelperMethods
include LazyHighCharts::LayoutHelper
# asset (image_path)
include ActionView::Helpers::AssetUrlHelper
include Sprockets::Rails::Helper
# chỉ định phạm vi tìm kiếm của asset
self.assets_prefix = Rails.application.config.assets.prefix
self.assets_environment = Rails.application.assets
## asset digest
self.digest_assets = Rails.application.config.assets[:digest]
# form
include ActionView::RecordIdentifier
include ActionView::Helpers::FormHelper
include ActionView::Helpers::FormOptionsHelper
## form_for
String.send :include, ActionView::Helpers::TextHelper
String.send :include, ActionView::Context
## form_for
def form_for(model, options, &block)
raw(super)
end
## fields_for
def fields_for(model, &block)
raw(super)
end
# i18n
include ActionView::Helpers::TranslationHelper
def scope_key_by_partial(key)
if key.to_s.first=="."
"cells.#{self.class.to_s.underscore}#{key}"
else
key
end
end
# model ở dạng số nhiều thì dùng alias
def models
model
end
# flash
def flash
parent_controller.flash
end
end
Nguồn tài liệu tham khảo :
All rights reserved