0

By example:

  • A Place belongs to a User.
  • An Event belongs to a User.
  • An Event belongs to (but is not required to have) a Place.

I'd like to validate that an Event's Place always has the same User as the Place itself.

Validations of this form seem fairly common, yet I always end up writing my own validator. I'll include my version below for completeness, but I feel there should be a convention.

davetapley
  • 17,000
  • 12
  • 60
  • 86

2 Answers2

2

If an Event always has the same User as the Place, perhaps you should be modelling the association like this:

User
  has_many :places
  has_many :events, through: :places

Place
  has_many :events
  belongs_to :user

Event
  belongs_to :place
  has_one :user, through: :place

Then you don't need a validation; the structure of the associations enforces that for free.

Update: Although Place is optional, I would still structure the associations like this! It sounds like you might want to break out the Null Object pattern. There are several ways you could implement it; perhaps Single Table Inheritance would be suitable.

Essentially, you would create a subclass NullPlace < Place, which would have some special behaviour (its name might be some placeholder like "not specified"), but in terms of the associations it would behave just like a regular Place so no validations required!

Andrew Haines
  • 6,574
  • 21
  • 34
  • Unfortunately that requires that an `Event` must have a `Place`, which is not required, hence the `place.nil?` check. Good suggestion though, I've updated my question to specify this. – davetapley Jan 25 '13 at 23:30
  • Sorry, I had only skimmed your answer. I've updated mine with a possible approach. – Andrew Haines Jan 26 '13 at 10:55
  • `NullPlace` is a great suggestion! And the tragedy is our system already has some *not real but actually place-holder* `Place`s! I just didn't think of extending it like this. Thanks! – davetapley Jan 26 '13 at 16:53
0

Inside my Event model:

validate :user_consistency

def user_consistency
  errors.add :place, 'must belong to same user as event' unless place.nil? or place.user == user
end
davetapley
  • 17,000
  • 12
  • 60
  • 86