Дублирующая ошибка ввода с несколькими запросами в одно и то же время - PullRequest
0 голосов
/ 02 мая 2019

Я тестирую свой код, он без проблем работает с одним запросом, но когда я пытаюсь отправить его по нескольким запросам одновременно, у меня появляется повторяющаяся ошибка. Я использую MySQL в качестве базы данных.

Модель

class Playtime < ApplicationRecord
  validates :local_id, uniqueness: true, allow_blank: true
end

Контроллер

Из этого

def create
    begin
      if !Playtime.where(local_id: params[:local_id]).exists?
        @playtime = Playtime.create!(playtime_params)
        json_response(@playtime.local_id,true)
      else
        json_response(params[:local_id], true)
      end
    rescue ActiveRecord::RecordInvalid => invalid
      json_response(invalid.record.errors.full_messages.first,false)
    end
  end

К этому я думал, что это будет исправлено с помощью этого.

def create
    begin
      if !Playtime.where(local_id: params[:local_id]).exists?
        @playtime = Playtime.create(playtime_params)
        if @playtime.valid?
          json_response(@playtime.local_id,true)
        else
          json_response(params[:local_id], true)
        end
      else
        json_response(params[:local_id], true)
      end
    rescue ActiveRecord::RecordInvalid => invalid
      json_response(invalid.record.errors.full_messages.first,false)
    end
  end

Но та же ошибка.

Мой запрос.

curl -X POST \
  http://localhost:3000/events/playtime \
  -H 'Content-Type: application/json' \
  -H 'Postman-Token: b4a636e9-5802-446f-9770-692895ebdbfd' \
  -H 'cache-control: no-cache' \
  -d '{
    "local_id": "664278-153"
}'&
curl -X POST \
  http://localhost:3000/events/playtime \
  -H 'Content-Type: application/json' \
  -H 'Postman-Token: b4a636e9-5802-446f-9770-692895ebdbfd' \
  -H 'cache-control: no-cache' \
  -d '{
    "local_id": "664278-153"
}'

Ошибка без передачи на спасение.

ActiveRecord::RecordNotUnique (Mysql2::Error: Duplicate entry '664278-153' for key 'index_playtimes_on_local_id': INSERT INTO `playtimes`

1 Ответ

3 голосов
/ 02 мая 2019

Проблема здесь:

if !Playtime.where(local_id: params[:local_id]).exists?
  # ⇒ SWITCH OF THE CONTEXT, RECORD CREATED BY ANOTHER PROCESS
  @playtime = Playtime.create!(playtime_params)

Обычно проверка проходит, а затем до create получает в базу данных другой процесс, обработавший одновременный запрос , который создал запись в базе данных.

Наиболее распространенным подходом для рельсов является использование Оптимистическая блокировка и спасение StaleObjectError , но здесь у вас уже есть ограничение на поле, так что это будет еще проще:

def create
  # no need to begin here, you might rescue the whole function body
  @playtime = Playtime.create!(playtime_params)
  json_response(@playtime.local_id, true)
rescue ActiveRecord::RecordNotUnique
    # record is already there, ok
    json_response(params[:local_id], true)
rescue ActiveRecord::RecordInvalid => invalid
    # params are invalid, report
    json_response(invalid.record.errors.full_messages.first, false)
end

Sidenote: мы обычно предоставляем код ошибки HTTP с отчетом об ошибке, ваш код в настоящее время, вероятно, обслуживает 200 OK в пределах «неверного» ответа.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...