Is there a straightforward way to replace a model based on a unique constraint?

With Rails 5, what's the most elegant way to write a replace save method based on a uniqueness constraint in my model? This is my model with the two columns that define a unique constraint

class Vote < ApplicationRecord
  belongs_to :person
  belongs_to :user

  validates_uniqueness_of :person, scope: [:user]
end

In my controller, I'd like to invoke logic to save a vote, by doing

  # Rate someone!
  def create
    user = current_user
    @vote = Vote.new(vote_params)
    @vote.user = user
    @vote.save!
  end

However the above doesn't work if the user has already voted on that person. In such a case, i'd like to delete their previous vote and create a new vote (or edit the existing one). Is there an easy way to do a transactional insert/update based on whether the unique constraint exists?

2 answers

  • answered 2018-01-16 23:03 Anurag Aryan

    You should use find_or_create_by.

    # Rate someone!
    def create
      @vote = Vote.find_or_create_by(person_id: vote_params[:person_id])
      @vote.user = current_user
      @vote.save!
    end
    

  • answered 2018-01-17 04:09 Ziv Galili

    I would go with first_or_create

    def create
      @vote = Vote.where(person_id: vote_params[:person_id], user: current_user).first_or_create.update(vote_params)
    end
    

    It will look for the Vote with the current User and Person, if it exists it will Update it, if it doesn't it will create it.

    (It will make only one INSERT)