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_addinHomewhich also raise an error;- validating these rules in
Phonedoes not make sense to me, as this rule is aHomeconcern
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.
