class EventInstance < ApplicationRecord
  # Virtual attribute for the parent event's name in case it is new
  attr_accessor :new_parent_event_name

  belongs_to :event
  has_many   :submissions

  default_scope { order :year }

  before_validation :set_parent_event

  validates :event, presence: true
  validates :year, uniqueness:   { scope: :event, message: 'should happen once per year' },
                   numericality: { only_integer: true }

  def name_and_year
    "#{event.name} #{year}"
  end

  private

  def set_parent_event
    if received_bad_event_params
      errors.add(:base, 'choose either an existing event or to create a new one')
    else
      event || create_event!(name: new_parent_event_name)
    end
  end

  def received_bad_event_params
    received_both_new_and_existing_events || received_neither_new_nor_existing_events
  end

  def received_both_new_and_existing_events
    event && new_parent_event_name.present?
  end

  def received_neither_new_nor_existing_events
    event.nil? && new_parent_event_name.blank?
  end
end

class EventInstance < ApplicationRecord
  # Virtual attribute for the parent event's name in case it is new
  attr_accessor :new_parent_event_name

  belongs_to :event
  has_many   :submissions

  default_scope { order :year }

  before_validation :set_parent_event

  validates :event, presence: true
  validates :year, uniqueness:   { scope: :event, message: 'should happen once per year' },
                   numericality: { only_integer: true }

  def name_and_year
    "#{event.name} #{year}"
  end

  private

  def set_parent_event
    if received_bad_event_params
      errors.add(:base, 'choose either an existing event or to create a new one')
    else
      event || build_event(name: new_parent_event_name)
    end
  end

  def received_bad_event_params
    received_both_new_and_existing_events || received_neither_new_nor_existing_events
  end

  def received_both_new_and_existing_events
    event && new_parent_event_name.present?
  end

  def received_neither_new_nor_existing_events
    event.nil? && new_parent_event_name.blank?
  end
end

Stop trying to save new Event before EventInstance validation
Stop trying to save new Event before EventInstance validation

By building the `Event` but not saving it, we’re now allowing it to get
autosaved when the `EventInstance` is successfully saved in future,
rather than pre-emptively trying to save it during the
`before_validation` callback.

This is better than what we were doing before, for two reasons:

1. We only want to really save a new `Event` if the `EventInstance` is
also successfully saved. Under the previous arrangement, if the
`EventInstance` failed to save for any reason (e.g. its validations
didn’t all pass) then we were relying on the transaction rollback to
prevent an unwanted `Event` hanging around in the database. This worked
but it makes more sense to avoid that situation in the first place.

2. A change in Rails 5.2.0 [1] makes `create` raise an exception on a
singular association (e.g. `belongs_to`) if the parent object isn’t
saved yet, so our previous use of `create_event!` will stop working when
we upgrade to Rails 5.2.0. This change in Rails was probably motivated
by point 1 above.

[1] https://github.com/rails/rails/commit/9048a70f34b8109be24b2da1009a2f4607ec66bf
