やりたいこと
gem 'cocoon'
を使ったStationレコードのedit画面内の営業時間登録フォームで、曜日の重複をバリデーションメッセージ表示したい
ベストプラクティスを調べてみたが見つからなかったので、親モデルでのカスタムバリデーションで実装する
モデル
### Stationモデル
class Station < ActiveRecord::Base
has_many :business_hours, inverse_of: :station, dependent: :destroy
validate :business_hours_day_of_week_is_uniq
def business_hours_day_of_week_is_uniq
day_of_week_ary, index_of_errors = [[], []]
business_hours.each_with_index do |bh, i|
next if bh.day_of_week.nil?
index_of_errors << i if day_of_week_ary.include?(bh.day_of_week)
day_of_week_ary << bh.day_of_week
end
index_of_errors.each{ |i| business_hours[i].errors.add(:day_of_week, '曜日が重複しています') }
end
end
### BusinessHourモデル
class BusinessHour < ActiveRecord::Base
belongs_to :station
enum day_of_week: { monday: 1, tuesday: 2, wednesday: 3, thursday: 4, friday: 5, saturday: 6, sunday: 7 }
end
フォーム
<div>
<%= link_to_add_association '営業時間を追加', f, :business_hours,
class: 'btn btn-success',
data: { association_insertion_node: '#business_hour-association-insertion-point', association_insertion_method: 'append' } %>
<div>※一つも登録がない場合は24時間営業扱いになります</div>
</div>
<table class="table table-list">
<tbody id='business_hour-association-insertion-point'>
<div class="form-group">
<%= f.fields_for :business_hours do |bh| %>
<%= render 'admin/stations/business_hour_fields', f: bh %>
<% end %>
</div>
</tbody>
</table>
<%# _business_hour_fields.html.erb %>
<tr class="nested-fields">
<td>
<%= f.select :day_of_week, BusinessHour.day_of_weeks_i18n.invert, {include_blank: true} %>
</td>
<td>
<%= f.text_field :from, placeholder: '「07:30」のように入力' %>
</td>
<td>
<%= f.text_field :to, placeholder: '「24:30」のように入力' %>
</td>
<td>
<%= link_to_remove_association '削除', f, class: 'btn btn-danger' %>
</td>
</tr>
コントローラー
def update
@station.assign_attributes(station_params)
station_valid = @station.valid?
business_hours_valid = true
@station.business_hours.each{ |bh| business_hours_valid = false if bh.errors.any? }
if station_valid && business_hours_valid
@station.update(station_params)
redirect_to [:admin, @station], notice: "#{Station.model_name.human}を更新しました。"
else
render :edit
end
end