DATE_SELECTをCHAR型のカラムに対応させる
DATE_SELECTをCHAR型のカラムに対応させる
Rubyには日付形式の入力フォームをサポートする
date_selectという機能が存在します。
こちら年・月・日を別々のプルダウンで表現してくれて便利な機能です。
ERBファイルの中に下のように書き込んで利用することが出来ます。
誕生日:<%= send(:date_select, "user", "brthday",:start_year => 1850, :end_year => Time.now.year, :use_month_numbers => true) %>
2月31日のようなありえない日付が入力できてしまうなど問題もありますが
問題を是正するプラグインもでているようです。
さて、このdate_selectですがちょっと残念な問題を抱えている
対応するmodelがRubyのDate型に対応するカラムでなければエラーで落ちてしまいます。
日付系の入力項目であっても、後の検索しやすさなどの為にCHAR型で保持したいと言うことはよくあります。
Date型系のカラムはDB上でもIndex評価がほとんどうまく行かないので
正直DBが専門の僕としてはまったく推薦できない状況です。
というわけで、どうしてもCHAR型のフィールドにdate_selectフィールドの検索結果を格納したかったので
Modelクラスに次のような補正を行うことで対応しました。
(1)MODELクラスのインスタンスフィールドにDATE型の値格納用変数を用意する。
class User < ActiveRecord::Base
attr_accessor :brthday_timestmp ##誕生日(デート型格納用)
end
(2)ERB中のDATE_SELECTに対応するフィールドの名称を(1)の変数に変更する。
誕生日:<%= send(:date_select, "user", "brthday_timestmp",:start_year => 1850, :end_year => Time.now.year, :use_month_numbers => true) %>
(3)MODELクラスにinitializeメソッドを作成する
class User < ActiveRecord::Base
##日付型ダミー変数の取得用関数、実態としては文字列の日付を変換して返す
def brthday_timestmp
if brthday != nil then
@brthday_timestmp = Date::new(brthday[0,4].to_i, brthday[4,2].to_i, brthday[6,2].to_i)
end
end
##日付型ダミー変数の設定用関数
def brthday_timestmp=(value)
@brthday_timestmp = value##文字列方の変数に格納
frmtStrng = '%Y%m%d'
attributes["brthday"] = @brthday_timestmp.strftime(frmtStrng)end
##属性の設定
def attributes=(attributes)if attributes != nil && attributes.has_key?("brthday_timestmp(1i)") then
if attributes["brthday_timestmp(1i)"].length > 0 then
##年・月・日の項目別にローカル変数に格納
year = attributes["brthday_timestmp(1i)"]
mnth = attributes["brthday_timestmp(2i)"]
day = attributes["brthday_timestmp(3i)"]##日付型の変数に格納
@brthday_timestmp = Date::new(year.to_i, mnth.to_i, day.to_i)##文字列方の変数に格納
frmtStrng = '%Y%m%d'
attributes["brthday"] = @brthday_timestmp.strftime(frmtStrng)
end
##パラメーターから日付関連KEYを削除
attributes.delete("brthday_timestmp(1i)")
attributes.delete("brthday_timestmp(2i)")
attributes.delete("brthday_timestmp(3i)")end
##スーパークラスを呼ぶ
super
end
##モデルクラス初期化用メソッド
def initialize(attributes = nil)##画面からの属性がわたってきて初期化されるときのみ
##日付型の変換処理を実行する
if attributes != nil then
attributes=(attributes)
endend
end
以上でうまく動くようになりました。
当初Modelクラスのインスタンス変数は作成していなかったのですが
(そんなものがあるのはかっこ悪いなぁと)
この場合、更新処理などにおいて、
インスタンスの保持値をdate_selectで受け取るところでエラーとなってしまうので
この形となりました。
なお、インスタンス変数の取得用メソッドは
実態としては文字列の日付を日付型に変換して戻すように作ります。
毎回記述Modelにしないといけないのがとっても面倒なので
ユーティリティー化したいのですがど、この方式では難しく
date_selectをいじったほうがはやそうです。
そのうち暇があれば挑戦してみます。