no_lyf_programmer
no_lyf_programmer

Reputation: 595

Rails validate polymorphic associated model attribute

In my Rails 5.2 app, I have a polymorphic model Vehicle of types Car, Bike, Jeep etc. which has belongs_to association vehicle_type. I would like to validate associated record attribute display_name. The following code snippet does the job but I would like to know a better way to do this.

class Car < Vehicle
      validates :vehicle_type,
        :inclusion => {
          :in => [VehicleType.find_by(display_name: 'four wheeler')],
          :message => "A Car can only be of vehicle_type 'four wheeler'",
        }
    }

Upvotes: 0

Views: 928

Answers (3)

Dylan Andrews
Dylan Andrews

Reputation: 296

I agree with Mathieu Larouche. One small thing I would add to this discussion is that this is not really a polymorphic association, as polymorphic associations are about how "a model can belong to more than one other model, on a single association". This is done via a combination of type and id fields (imageable_id and imageable_type, for example). See docs here.

It doesn't really affect the response your question, but I just wanted to mention it because polymorphic associations took me forever to wrap my head around, and I thought calling out the distinction could be helpful.

Upvotes: 0

Patrick Barattin
Patrick Barattin

Reputation: 627

I don't know what is the best way, but I'll share what i have done in one of my projects:

I decided to extend ActiveModel::Validator and create my own validation for my polymorphic associations

In you case

class CarValidator < ActiveModel::Validator 
  def validate_vehicle_type(record)
     # where did you save the veicle type associatuon?
     unless VehicleType.find_by(display_name:  record.veicle_type).exists?
    record.errors.add :veicle_type, "This veicle type does not exist"
  end 
end

then validates with CarValidator

Upvotes: 0

Mathieu Larouche
Mathieu Larouche

Reputation: 131

You should put the validation on the id rather than the display name since you would have to refactor your code if you ever decide to change the display name.

class VehiculeType
  FOUR_WHEELER = 1 (id of the four_wheeler type)
end

class Car < Vehicule
  validate :validate_vehicule_type

  private

  def validate_vehicule_type
   errors.add(:vehicule, "A Car can only be of vehicle_type 'four wheeler'") unless vehicule_type_id == VehiculeType::FOUR_WHEELER
  end

end

Upvotes: 0

Related Questions