1

Having trouble with accepting nested attributes when I've changed the class name. I'm sure I am just missing something obvious but just can't seem to find it.

models/walk.rb

class Walk < ApplicationRecord
  has_many :attendees, class_name: 'WalkAttendee', foreign_key: "walk_id", dependent: :destroy

  validate :has_attendees
  accepts_nested_attributes_for :attendees

  def has_attendees
    errors.add(:base, 'must add at least one attendee') if self.attendees.blank?
  end
end

models/walk_attendee.rb

class WalkAttendee < ApplicationRecord
  belongs_to :walk
end

test/models/walk_test.rb

class WalkTest < ActiveSupport::TestCase
  test 'walk can be created' do
    walk = Walk.new(walk_params)
    assert walk.save
  end

private

  def walk_params
    {
      title: 'Rideau Walk',
      attendees_attributes: [
        { name: 'John Doe', email: 'john-doe@test.ca', phone: '123-321-1234', role: :guide },
        { name: 'Jane Doe', email: 'jane-doe@test.ca', phone: '123-321-1234', role: :marshal }
      ]
    }
  end
end
  • 1
    Its a conundrum. You can't save a Walk unless it has any attendees and you cannot associate anything with a walk unless it has been saved and has an ID. You need to rethink your approach. Also `blank?` is for testing user input (strings) for associations and arrays you should use `any?` – max Mar 04 '18 at 21:26
  • Can you expand upon " when I've changed the class name"... did it work before, but has changed since you changed the classname? If so, what was it before? Are you sure that's what broke it? because I'm looking askance at the validation - can you double check that by removing it temporarily and seeing if it Just works? – Taryn East Mar 04 '18 at 22:09
  • Ugh... thanks for the little push @max, @TarynEast `blank?` was making a false positive in some of my other tests. `validates :walk_attendees, length: { minimum: 1 }` was what I needed. – Tyler Rowsell Mar 05 '18 at 02:19

2 Answers2

3

If, just like me, other people arrive on this thread because they're facing an issue with nested attributes and has_many relationship (with Rails 5.2 / Rails 6), my problem was fixed by using inverse_of:

My initial problem:

class PriceList
  has_many :lines, foreign_key: "price_list_id", class_name: "PriceListLine", dependent: :destroy
  accepts_nested_attributes_for :lines, allow_destroy: true
end

class PriceListLine
  belongs_to :price_list
end

PriceList.new(lines: [{..}]).valid?
# --> false. Error = price_list_line.attributes.price_list.required

I fixed it by adding inverse_of: "price_list" to the has_many relationship:

has_many :lines, inverse_of: "price_list", foreign_key: "price_list_id", class_name: "PriceListLine", dependent: :destroy
Dharman
  • 30,962
  • 25
  • 85
  • 135
Pierre-Yves O.
  • 508
  • 3
  • 15
1

I was going about the validation all wrong. Thanks to @max and @TarynEast for the push in the right direction.

validates :attendees, length: { minimum: 1 }

Did the trick. Didn't know this validation existed. :D