Rails validate uniqueness fails on concurrent inputs

前端 未结 2 1409
清歌不尽
清歌不尽 2020-12-20 03:50

I have a Ticket model with basic uniqueness validation on a string attribute ticket_number

validates :ticket_number, uniqueness: t         


        
相关标签:
2条回答
  • 2020-12-20 04:14

    @Yule answer was very helpful , it explained Why this happened and that adding database level constraint will prevent it.

    The docs says, this will throw an ActiveRecord::RecordNotUnique exseption which i don't want the users to see ofcourse, so here is exactly how to apply the workaround suggested by @Yule:

    1. Add an index on the attribute

      add_index(:tickets, :ticket_number, :unique => true)

    2. Adjust the controller#create action to catch the db exception:

    def create
     @ticket = Ticket.new(ticket_params)
     if @ticket.save
       flash[:success] = 'Ticket was successfully created.'
     else
       render action: 'new'
     end
     #catch the exception
     rescue ActiveRecord::RecordNotUnique
       flash[:danger] = 'The ticket number you entered is already taken !'
       render action: 'new'
    end
    

    Same should be done for controller#update action ofcourse

    0 讨论(0)
  • 2020-12-20 04:20

    This is very uncommon and you're probably very unlucky that it has, it is possible.

    Read: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/validations/uniqueness.rb#L165

    Consider the following: User A submits form

    • User A submits form
    • Rails checks database for existing ID for User A- none found
    • User B submits form
    • Rails checks database for existing ID for User B- none found
    • Rails Saves user A record
    • Rails saves user B record

    All this has to happen within milliseconds but it is technically possible.

    I'd suggest adding a constraint at the database level (primary key).

    0 讨论(0)
提交回复
热议问题