経緯
親モデルと同時に子モデルを保存するときに超便利なnested_formというgemがあります。
https://github.com/ryanb/nested_form
たまたま、以下のような仕様を実装する機会がありました。
- 自由に子の数は変えられる
- 最大でも5個に抑える
- 何番目のフィールドかを表示する
その方法をば。
nested_formの使い方
こちらをご参照ください。
上限の決め方
実はやり方が公式に載っています。
How To: Limit max count of nested fields
ここにあるとおり、
$(function() {
$(document).on('nested:fieldAdded', function(e) {
var link = $(e.currentTarget.activeElement);
if (!link.data('limit')) {
return;
}
if (link.siblings('.fields:visible').length >= link.data('limit')) {
link.hide();
}
});
$(document).on('nested:fieldRemoved', function(e) {
var link = $(e.target).siblings('a.add_nested_fields');
if (!link.data('limit')) {
return;
}
if (link.siblings('.fields:visible').length < link.data('limit')) {
link.show();
}
});
})
をAssetとして読み込んでやるだけです。
個人的に、coffeeで全部書いてるのに一つだけjsってのも気持ちが悪いので、書き直したのがこちらです。
$ ->
do window.nestedFormLimitter = ->
$(document).on 'nested:fieldAdded', (e) ->
$link = $(e.currentTarget.activeElement)
if (!$link.data('limit'))
return
if ($link.siblings('div.fields:visible').length >= $link.data('limit'))
$link.hide()
$(document).on 'nested:fieldRemoved', (e) ->
$link = $(e.target).siblings('a.add_nested_fields')
if (!$link.data('limit'))
return
if ($link.siblings('div.fields:visible').length < $link.data('limit'))
$link.show()
あとはViewファイルの追加ボタンに以下のようにdata-link属性にリミットの個数を入れてやるだけです。
f.link_to_add '追加' :members, data: { limit: 5 }
フィールドの順番を表示する
フィールドの順番を表示するだけであれば、特に表示Ruby側で使えるようにする必要がないので、上記のCoffeeScriptに追記しました。
$ ->
do window.nestedFormLimitter = ->
# フィールドの番号を振って、表示する関数
do setFieldNum = ->
$('div.fields:visible').each ->
$('h3 span.order-num', $(@)).text($('div.fields:visible').index(this) + 1)
$(document).on 'nested:fieldAdded', (e) ->
setFieldNum() # 追記
$link = $(e.currentTarget.activeElement)
if (!$link.data('limit'))
return
if ($link.siblings('div.fields:visible').length >= $link.data('limit'))
$link.hide()
$(document).on 'nested:fieldRemoved', (e) ->
setFieldNum() # 追記
$link = $(e.target).siblings('a.add_nested_fields')
if (!$link.data('limit'))
return
if ($link.siblings('div.fields:visible').length < $link.data('limit'))
$link.show()
解説
nested_formではフォームが追加されたときはnested:fieldAdded、削除されたときはnested:fieldRemovedというイベントが発火します。
$linkはこのイベントを発火させたボタンのDOMが入っていて、一定数を超えているとき、非表示にして、同時に番号を表示させています。
ただ、ここで、一点注意なのは、クライアント側でDOMを操作してやるようなことをされてしまっては、必ずしも上限の個数のみのデータが飛んで来るわけではありません。
ちゃんと、モデル側でもバリデーションをかけてやりましょう。
以下は個数が大きすぎたときに弾くバリデーションの一例です。
class Group < ActiveRecord::Base
validate :member_presence
private
def member_presence
unless self.members.size <= 5
errors.add(:base, "メンバー多すぎ!エグザイルか!")
end
end
end
仮にDOMを操作されても「メンバー多すぎ!エグザイルか!」と表示されます。1
まとめ
- 公式をよく見れば意外とちゃんと載ってる
- JSのバリデーションに頼りきらず、ちゃんとModelでもバリデーションを書く
以上で個数の上限を決めると同時にフィールドの番号を表示できるようになります。
公式のWikiはひとまず、チェックしてみる癖を付けてもいいかもしれませんね。
- 「Choo Choo TRAIN」を歌いながら女の子に「チューしてよ!」って叫んでた友達を思い出しました。 ↩
コメントを残す