0
0

More than 1 year has passed since last update.

Railsで子レコードを複数同時保存する際のバリデーション

Last updated at Posted at 2022-09-30

やりたいこと

gem 'cocoon'を使ったStationレコードのedit画面内の営業時間登録フォームで、曜日の重複をバリデーションメッセージ表示したい
image.png

ベストプラクティスを調べてみたが見つからなかったので、親モデルでのカスタムバリデーションで実装する

モデル

### 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

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0