简体   繁体   中英

Guarantee that model is associated to same parent

Assuming i have 3 models associated to each other:

class Farm < ApplicationRecord
  has_many :horses
  has_many :events
end

class Horse < ApplicationRecord
  belongs_to :farm
  has_many :events_horses, class_name: 'Event::EventsHorse'
  has_many :events, through: :events_horses, source: :event, dependent: :destroy
end

class Event
  belongs_to :farm
  has_many :events_horses, class_name: 'Event::EventsHorse'
  has_many :horses, through: :events_horses, source: :horse, dependent: :destroy
end

class Event::EventsHorse < ApplicationRecord
  self.table_name = "events_horses"

  belongs_to :horse
  belongs_to :event

  audited associated_with: :event, except: [:id, :event_id]
end

How to guarantee that each of the Horse belongs to same Farm as event? Possible solution is using custom validation, but i was wondering if there is some other way. I have few other models like Horse, so it force me to do custom validation method to each of them.

class Event
  ...
  validate :horses_belongs_to_farm

  private

  def horses_belongs_to_farm
    horses.all? {|h| h.farm_id == farm_id}
  end   
end

I think the model you are using is setting up too many id's between the tables that require consistency checking.

If you set the model up this way, then you don't need to validate that a horse's farm and event are consistent since the data ensures it:

class Farm < ApplicationRecord
  has_many :horses
  has_many :events
end

class Horse < ApplicationRecord
  belongs_to :farm
  has_many :events, through: :farm
end

class Event < ApplicationRecord
  belongs_to :farm
  has_many :horses, through: :farm
end

If you need efficient access to horses from events or events from horses, you can use joins. This gives some simplicity, clarity, and consistency.

You should also have a look at Choosing Between has_many_through and has_and_belongs_to_many .


[Edit based upon updated question and comments] Now that your model and question are a little more clear, my hunch is that putting the validation in the Event model causes redundant validations. Since your intent is to make sure that, in a given event, the horse and farm are consistent, I would put the validation in EventsHorses :

 class Event::EventsHorse < ApplicationRecord ... validate :horse_belongs_to_farm private def horse_belongs_to_farm horse.farm_id == event.farm_id end end 

As an aside, thy do you have Event::EventsHorse rather than simply have a separate model for EventsHorse ?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM