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
inHome
which also raise an error;- validating these rules in
Phone
does not make sense to me, as this rule is aHome
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.