Ruby の基本は DRY ということで,同じことは繰り返さないために,単純な作業でも繰り返しそうなものはメソッドにまとめています.特に,Rails の場合には,以下のように共通なメソッドを書いておく場所が用意されています.
- app/controller/application_controller.rb
- コントローラで共通なメソッドを書いておける
- app/helper/application_helper.rb
- ビューで共通なメソッドを書いておける
私の場合は,コントローラでもビューでも使うようなメソッドは lib の下に misc_method.rb として,モジュールを用意しています.昨日の create_delete_check の中でも ncm とかを使ってしまっていました.ということで,多数のメソッドが記載されている中で,システムに依存しないものを抽出して紹介しておきます.
app/controller/application_controller.rb
# vim:set fileencoding=utf-8 filetype=ruby: class ApplicationController < ActionController::Base rescue_from DeviseLdapAuthenticatable::LdapException do |exception| render text:exception, status:500 end protect_from_forgery (中略:ここにはユーザ権限に対応した大量のフィルタが書かれている.CanCan を導入すべきか?) # パラメータからオブジェクトを取得する # 使い方: @campus, @gakunen, @ids = get_parameters_and_ids [ [ Campus, :id ], [ Gakunen, :gakunen_id ] ] def get_parameters_and_ids(parameter_array) ans = [] ids = {} parameter_array.each do |pa| c, id = pa unless params[id] == nil ans << c.find(params[id]) ids[id] = params[id] else ans << nil end end ans << ids end # ダウンロード時における IE のファイル名文字化けを回避する def IEpatch(fname) /MSIE/ =~ request.env['HTTP_USER_AGENT'] ? CGI.escape(fname) : fname end # excel で出力 def output_excel(template, fname = nil) @excel_page = true options = fname ? { filename:IEpatch(fname)} : {} send_data(render_to_string(template:template, layout:'excel.html'), options) end # ロックされていなければ PDF を作成する # BatchLock は後日紹介 def make_pdf_with_lock(fname) begin BatchLock.run(:output_pdf) do yield output_pdf fname end rescue processing_pdf fname end end # LaTeX で作成した PDF ファイルを出力する # PlatexPdf も後日紹介 def output_pdf(fname) pdf = PlatexPdf::OutputPdfName send_file pdf, filename:IEpatch(fname), disposition:'inline' end # 作業中という PDF ファイルを出力する def processing_pdf(fname) send_file 'tex/processing.pdf', filename:IEpatch(fname), disposition:'inline' end end
app/helper/application_helper.rb
# vim:set fileencoding=utf-8 filetype=ruby: module ApplicationHelper # 再帰パスを作成 def recursive_path(ids = {}, option = {}) request.symbolized_path_parameters.merge(ids).merge(option) end # key を除いた再帰パスを作成 def recursive_path_without_key(ids, key) ans = request.symbolized_path_parameters.merge(ids) ans.delete(key) ans end # excel 書き出しのパスを作成 def export_excel_path(ids = {}, option = {}) recursive_path(ids, option.merge(format:'xls')) end NumberOfSplitTables = 6 # 長い配列を適当な長さに分割しながら yield する def split_yield(array, n = NumberOfSplitTables) until ((sub_array = array.slice!(0, n)).length == 0) do yield(sub_array) end end # よく使うテーブルヘッダを表示 def link_title render inline:<<-HAML, type: :haml %tr %th リンク %th 内容 %th 権限 HAML end # date から曜日を得る def jweek(date) %w(日 月 火 水 木 金 土)[date.wday] end # date から ○月○日を得る def mgdn(date) "#{date.month}月#{date.day}日" end # date から ○月○日(曜)を得る def mgdnw(date) "#{mgdn(date)}(#{jweek(date)})" end end
lib/misc_method.rb
# vim:set fileencoding=utf-8 filetype=ruby: module MiscMethod # nil_check.nil の時に別のメッセージを出す def nc(o, n = nil) o ? o : n end # nil_check.nil でなければ yield の返値. def ncm(o, n = nil) o ? yield(o) : n end # 0 なら表示しない def zero_null(o) o == 0 ? "" : o end # array から hash を得る.例: name_hash = array_to_hash(array) { |x| [ x.name, x ] } def array_to_hash(array) ans = {} array.each do |item| k, v = yield(item) ans[k] = v end ans end # array の hash から key に対応した array を得る def array_from_hash_array(hash_array, key) hash_array[key] ||= [] end # array から array の hash を得る def array_to_hash_array(array) ans = {} array.each do |item| k, v = yield(item) array_from_hash_array(ans, k) << v end ans end # hash の hash から key に対応した hash を得る def hash_from_hash_hash(hash_hash, key) hash = hash_hash[key] || hash_hash[key] = {} end # hash の hash に オブジェクトを挿入する def set_object_to_hash_hash(hash_hash, object, key1, key2) hash = hash_from_hash_hash(hash_hash, key1) hash[key2] = object end # array の hash の hash にオブジェクトを挿入する def set_object_to_hash_hash_array(hash_hash_array, object, key1, key2) hash_array = hash_from_hash_hash(hash_hash_array, key1) array = array_from_hash_array(hash_array, key2) array << object end # 配列の内容を累計 def array_sum(array) ans = 0 array.each do |n| ans += n if n.class == Fixnum end ans end # 小数点以下 2 位を四捨五入する (format "%4.1f", 8.45 などでは正しく四捨五入されないため) def round1(num) (num * 10).round / 10.0 end # flag から ○×を得る def mb_options_for_select [ [ '○', true ], [ '×', false ] ] end # flag から ○×を得る def mb(flag) flag ? '○' : '×' end # flag から ○を得る def mn(flag) flag ? '○' : '' end end
用途が多岐にわたっており,細かく説明することができなくてすみません.また関連するネタが出たらそこで説明できればと思います.