[Rails] 小技巧 Rails Tips
keywords: helper
[TOC]
常用
- [判斷內容是空或有]([Rails] 判斷內容是空或有.md)
- [判斷物件有哪些方法?上一層是誰?屬於哪個型態]([Rails] 判斷物件有哪些方法?上一層是誰?屬於哪個型態.md)
其他
清除 Rails 內的快取(Cache)
# 必要時需要手動 rm -rf 刪除
$ rails log:clear
$ rake tmp:clear
$ rm -rf tmp/cache tmp/data tmp/miniprofiler
檢視 secret / credentials 檔案
$ EDITOR="sublime -w" rails credentials:edit
$ EDITOR=vim rails credentials:edit
SCSS 載入圖片
在 SCSS 中使用圖片 url 時,需使用 image-url 這個 helper,否則開發環境看得到,但到 production mode 就會炸掉:
.banner {
background: image-url('banner.png') center center no-repeat;
}
How to reference images in CSS within Rails 4 @ StackOverflow
如果是在 Webpacker 中要用圖片,可以使用 url() 搭配 ~ 前綴指向 assets 路徑:
// 圖片路徑 app/assets/images/event-header-bg.png
background-image: url('~images/event-header-bg.png');
自訂錯誤訊息樣式(Customize Field Error)
# ./config/environment.rb
ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
html_tag.html_safe
end
Customize Field Error in Rails 5 @ Ruby Plus
Methods
陣列(Array)
元素分群
# 把 @products 這個大陣列以 3 個為一組拆成小陣列,不足的用 false 填補
Array.in_groups_of(3, false){|group|}
取得陣列元素數目
# 取得陣列元素數目建議使用 size 效能較好(替代掉 count 或 length)
Order.all.size
產生 Secure Token
在建立某欄位的時候自動產生 Token:
# ./app/models/event.rb
class Event < ApplicationRecord
validates_uniqueness_of :authentication_token
before_create :generate_unique_secure_token
private
def generate_unique_secure_token
# return if self.authentication_token.present?
loop do
token = SecureRandom.base58(24)
self.authentication_token = token
break token unless Event.find_by(authentication_token: token)
end
end
end
驗證該 token 是否符合格式:
# ./app/controllers/api_controller.rb
def token_format_valid?(authentication_token)
base58_alphabet = ("0".."9").to_a + ("A".."Z").to_a + ("a".."z").to_a - ["0", "O", "I", "l"]
(authentication_token.split('') - base58_alphabet).blank? && authentication_token.size == 24
end
View Helper
<!-- 刪減多於字數 -->
<%= truncate("Once upon a time in a world far far away", length: 17) %>
<!-- 檢驗路由是否為 -->
<% current_page?(controller: 'shop', action: 'checkout', order: 'desc', page: '2') %>
<% current_page?('/shop/checkout') %>
- ActionView URL Helpers @ RailsAPI
常用變數
<!-- in erb file -->
<%= root_url %> <!-- 取得根網址 -->
<%= controller_name %> <!-- 取得 controller 名稱 -->
<%= action_name %> <!-- 取得 action 的名稱 -->
動態 i18n
# zh-TW.yaml
form:
en: 英文
zh-TW: 中文
<!-- 直接使用 t("form.#{...}") 即可動態使用 i18n
<% I18n.available_locales.each do |locale| %>
<%= t("form.#{locale}") %>
<% end %>
避免 HTML Encode
<%= raw(data) %>
<%= string.html_safe %>
如果有傳入 local_variable 才使用該變數
keywords: local_assigns
<!-- Without default value -->
<% if local_assigns.has_key? :headline %>
Headline: <%= headline %>
<% end %>
<!-- With default value -->
<% some_local = default_value if local_assigns[:some_local].nil? %>
Optional local variables in rails partial templates @ StackOverflow
使用 content_tag 自定義元素
在 do...end block 中如果希望有 if 判斷,可以在 end 後面使用 if
<%= content_tag :p, 'Hello', class: 'mb-1' %>
<!-- 使用 do end block -->
<%= content_tag :p, class: 'mb-1' do %>
<i class="fas fa-fw fa-globe"></i>
<%= link_to 'Website', @event.website, class: 'pl-2', target: :_blank %>
<% end if @event.website.present? %>
使用 radio 和 label
keywords: f.radio_button, label_tag
<div class="form-group">
<label>Gender</label>
<div class="w-100"></div>
<div class="custom-control custom-radio custom-control-inline">
<%= f.radio_button :gender, 'male', checked: @personal_info.gender == 'male', class: 'custom-control-input' %>
<%= label_tag 'personal_info_gender_male', 'Male', class: 'custom-control-label' %> </div>
<div class="custom-control custom-radio custom-control-inline">
<%= f.radio_button :gender, 'female', checked: @personal_info.gender == 'female', class: 'custom-control-input' %>
<%= label_tag 'personal_info_gender_female', 'Female', class: 'custom-control-label' %> </div>
</div>
選擇國家的下拉選單(select)
# app/helpers/common_helper.rb
def country_options(selected = nil, options = nil, locale = I18n.locale)
options =
if options.blank?
ISO3166::Country.translations(locale).sort.to_h.invert.entries
else
ISO3166::Country.translations(locale).select{ |k, v| options.include?(k) }.sort.to_h.invert.entries
end
options_for_select(options, selected)
end
<!-- _form.html.erb -->
<div class="form-group">
<%= f.label :country, class: 'col-form-label fz-13 text-muted' %>
<%= f.select(:country, country_options(event.country), { prompt: '- 請選擇 -' }, { class: 'custom-select' }) %>
<div class="invalid-feedback feedback-icon">
<i class="fas fa-exclamation-triangle"></i>
</div>
</div>
在 partial / template 中使用 yield 和 content_for
這是 partial / template,在這裡面的 <%= yield %> 一定要寫在其他有名稱的 <%= yield :foo %> 之前,才能把要 render 它的樣板的內容帶進來:
<%# ./app/views/shared/_navbar.html.erb %>
<div>
<!-- 沒有名稱的 yield 一定要寫在最前面 -->
<%= yield %>
<ul class="left">
<%= yield :before_left_nav %>
<li>Some items ...</li>
<%= yield :after_left_nav %>
</ul>
<ul class="right">
<%= yield :before_right_nav %>
<li>Some items ...</li>
<%= yield :after_right_nav %>
</ul>
</div>
這是要 render 上面這個 partial 的樣板,在 render 後 do ... end 中的所有內容都會帶入到 _navbar.html.erb 裡面的 <%= yield %> 裡面,在從中看要對應到哪個有名稱的 yield:
<%# ./app/views/pages/tester.html.erb %>
<%= render 'shared/navbar', navbar_class: 'navbar-darker-background' do %>
<% content_for :before_left_nav do %>
<li class="nav-item">
<%= link_to 'Before', products_path, class: "nav-link #{'active' if action_name == 'products'}" %>
</li>
<% end %>
<% content_for :after_left_nav do %>
<%# ... %>
<% end %>
<% content_for :before_right_nav do %>
<%# ... %>
<% end %>
<% content_for :after_right_nav do %>
<%# ... %>
<% end %>
<% end %>