ここのチップは、Model内でのバリデートの自作です。 バリデートしたいのにバリデートメソッドがないと自作するしかありません。
Modelでvalidate 1
自作したバリデートメソッドでバリデートしてもらうには
validate :自作メソッド名と記述します。
アップロードするファイルの拡張子でバリデートする
ここで作るバリデートの仕様は
- ファイルのアップロードでファイルの拡張子をチェックし、決められた種類のファイルしかアップロードできない。
- ログインユーザーによってアップロードできるファイルの種類を変える。
というバリデートメソッドを作ります。そしてそのバリデートに対応するメッセージも表示されるようにします。
まず拡張子のリストを作っておきそのリストを使ってチェックします。許可する拡張子を変えたいときにはリストの部分を変更します。
ここで%wは、引数の文字列をスペース区切りで配列にする%記法の一つです。
1
2
3
4
5
6
7
def extension_white_list
%w(pdf xls xlsx doc docx ppt pptx pps ppsx)
end
def extension_white_list_for_host
%w(pdf txt)
end
バリデートメソッドの定義では、拡張子のリストを読み込みファイル名の拡張子がリスト内に存在すれば true を返し終了しますが、最後まで存在しなければ errors.add し、 false を返します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def upload_file_ext
return false if self.name.blank?
if is_for_host?
white_list = extension_white_list_for_host
else
white_list = extension_white_list
end
white_list.each do |ext|
if File.extname(self.name) == ".#{ext}"
return true
end
end
errors.add(:name, 'の拡張子が正しくありません。')
return false
end
上の実装では、hostユーザーの場合とその他ユーザーとでアップロードできるファイルの拡張子を変えています。hostでログインしアップロードする時には「 set_for_host true 」をコントローラーで実行します。
def is_for_host? @for_host end @for_host = false def set_for_host host if host @for_host = true end end定義したバリデートメソッド(upload_file_ext)をバリデート時に実行させるには
validate :upload_file_extのように記述します。
errors.add について
add(attribute, message = :invalid, options = {})もちろんバリデートされたとき表示されるメッセージを記述するのですが、第1引数(先の例では :name )は、どのように使われるのでしょうか。少し調べてみました。
このメッセ-ジは、第1引数(モデルの属性名)を翻訳した値に第2引数をつなげて作られます。 同じように第2引数にシンボルを指定した時にも翻訳された値が使われます。
どのように翻訳されるかというと、
config/application.rb で、
config.i18n.default_locale = :jaのように :ja を指定していたら
- config/locales/en.yml
- config/locales/ja.yml
- config/locales/attributes.ja.yml
といったYAMLファイルから「:ja」というnamespace内を検索して目的のキーに対応する値を見つけて翻訳します。 また、ファイルを探すロードパス(上記のconfig/locales がデフォルト)は、 config.i18n.load_path で指定して変更することができます。
errors.add の第1引数では、メッセージを追加したい属性の名前(上の場合では:name)が定義されているかを探して、見つかればそれを使います。見つからなかった場合は属性名(name)がそのまま使われます。
今の例であれば、
ja: activerecord: models: user: "ユーザー管理" material: "ファイル" attributes: user: name: "ログインID" material: name: "ファイル名"の中からモデル名がmaterialなので ja.attributes.material.name を見つけて「ファイル名」と翻訳してくれるわけです。
また、もし第2引数にシンボルが使われた場合には、 ja.errors.messages.キー名 を見つけて翻訳し、もし第2引数が省略されていたら、ja.errors.messages.invalid が使われます。