Home > Software engineering >  has_many through size validations
has_many through size validations

Time:02-01

I work on a booking application, where each Home can have several Phone. I would like to limit the number of Phone by Home to 3, and display a nice error in the create phone form.

How can I achieve that, in a rails way ?


code

class Phone < ApplicationRecord
  belongs_to :user
  validates :number, phone: true

  # validates_associated :homes_phones

  has_many :homes_phones, dependent: :destroy
  has_many :homes, through: :homes_phones

end


class User < ApplicationRecord
  has_many :phones, dependent: :destroy
end

class HomesPhone < ApplicationRecord
  belongs_to :home
  belongs_to :phone
  validate :check_phones_limit

  def check_phones_limit
    errors.add(:base, "too_many_phones") if home.phones.size >= 3
  end

end

specs

  it 'should limit phones to 3' do
    user = create(:user)
    home = create(:home, :active, manager: user)
    expect(home.phones.create(user: user, number: " 33611223344")).to be_valid
    expect(home.phones.create(user: user, number: " 33611223345")).to be_valid
    expect(home.phones.create(user: user, number: " 33611223346")).to be_valid

    # unexpectedly raises a ActiveRecord::RecordInvalid
    expect(home.phones.create(user: user, number: " 33611223347")).to be_invalid
  end

Side notes

My understanding of the flow is:

  • a transaction opens
  • phone attributes are validated (and valid)
  • phone is created, a primary key is available
  • homes_phone is saved! and an error is raised because the validation fails
  • the all transaction is rolled back, and the error bubble up

I have tried:

  • has_many before_add in Home which also raise an error;
  • validating these rules in Phone does not make sense to me, as this rule is a Home concern

CodePudding user response:

This is the rails way of doing this, in your Home class

validates :phones, length: { maximum: 3, message: "too many phones" }

CodePudding user response:

You could think validation is something like this: it target to the Model we want to create directly.

In your case, you want to validate when create phones, so you have to put the validation rule into the Phone model.

This way the validation will take effect, and you could get the error message correctly.

  • Related