Andy Harvey
Andy Harvey

Reputation: 12653

How to prevent duplicate records being created, but all other before_create methods to run?

A Rails app has an Event and Vote model. Events should be unique.

If a User attempts to create an Event that already exists, save should be prevented, and instead a Vote should be created for the existing Event.

I can prevent the Event from being saved using a custom validation or a before_create action. However, this also prevents the create_vote_on_existing_event method from being run.

Is there a way to selectively run methods when before_create returns false?

My models look something like this

class Event
  has_many :votes
  before_create :check_event_is_unique
private
  def check_event_is_unique
    if Event.where( attributes_to_match).any?
      errors.add(:base, :duplicate)
      create_vote_on_existing_event
      return false
    end
  end

  def create_vote_on_existing_event
    event = Event.where( attributes_to_match).last
    self.user.vote_on event 
  end
end
class Vote
  belongs_to :event
end

Upvotes: 0

Views: 1673

Answers (1)

Dawcars
Dawcars

Reputation: 368

You need a custom validator. Something like this might be suitable:

class Event
    validate :check_event_is_unique, :on => :create
    after_create :create_vote_on_existing_event

    def check_event_is_unique
      if Event.where( attributes_to_match).any?
          errors.add(:base, :duplicate)
          return false
      end
    end
end

You can also have your after_create for other methods.

More information on custom validation methods can be found here: http://guides.rubyonrails.org/active_record_validations.html#custom-methods

EDIT: One option is to pass validate: false to the save method. api.rubyonrails.org/classes/ActiveRecord/Validations.html

Another option is after_validation. This could call your create_vote_on_existing_event if your validation fails. The order of callbacks is as follows:
before_validation
after_validation
before_save
before_create
after_create
after_save
after_commit

after_validation is the last thing to run if validations fail, so you should be able to run some code from there.

Upvotes: 1

Related Questions