validates_uniqueness_of сбой на герою? - PullRequest
1 голос
/ 11 марта 2011

В моей модели User у меня есть:

validates_uniqueness_of: fb_uid (я использую Facebook Connect).

Однако иногда я получаю повторяющиеся строки при регистрации пользователя. Это очень плохо.

Время создания двух записей находится в пределах 100 мс. Я не смог определить, происходит ли это в двух отдельных запросах или нет (запись в журнал heroku отстой, и он возвращается только к этому моменту, и это происходит только дважды).

Две вещи:

  • Иногда запрос занимает некоторое время, потому что я запрашиваю в FB API информацию об имени, друзьях и фотографии.
  • Я использую bigint для хранения fb_uid (backend - postgres).

Мне не удалось воспроизвести в dev.

Любые идеи будут чрезвычайно признательны.

Функция входа в систему

def self.create_from_cookie(fb_cookie, remote_ip = nil)
    return nil unless fb_cookie
    return nil unless fb_hash = authenticate_cookie(fb_cookie)
    uid = fb_hash["uid"].join.to_i

    #Make user and set data
    fb_user = FacebookUser.new
    fb_user.fb_uid = uid
    fb_user.fb_authorized = true
    fb_user.email_confirmed = true
    fb_user.creation_ip = remote_ip
    fb_name_data, fb_friends_data, fb_photo_data, fb_photo_ext = fb_user.query_data(fb_hash)
    return nil unless fb_name_data
    fb_user.set_name(fb_name_data)
    fb_user.set_photo(fb_photo_data, fb_photo_ext)

    #Save user and friends to the db
    return nil unless fb_user.save
    fb_user.set_friends(fb_friends_data)
    return fb_user
end

Ответы [ 3 ]

1 голос
/ 11 марта 2011

Я не очень знаком с Facebook Connect, но возможно ли получить два одинаковых uuid, если два отдельных пользователя из двух разных учетных записей отправляют запрос в очень быстрой последовательности до того, как любой запрос будет завершен?(Иначе известный как условие гонки) validates_uniqueness_of все еще может страдать от этого типа гонки, подробности можно найти здесь:

http://apidock.com/rails/ActiveModel/Validations/ClassMethods/validates_uniqueness_of

Поскольку эта проверка выполняется внеВ базе данных все еще существует вероятность того, что повторяющиеся значения будут вставлены в две параллельные транзакции.Чтобы гарантировать это, вы должны создать уникальный индекс на поле.См. Add_index для получения дополнительной информации.

Вы можете действительно убедиться, что этого никогда не произойдет, добавив ограничение базы данных.Добавьте это в миграцию базы данных и затем запустите ее:

add_index :user, :fb_uid, :unique => true

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

0 голосов
/ 11 марта 2011

Кажется, в вашем коде есть какое-то состояние гонки.Чтобы проверить это, я сначала изменил бы код так, чтобы значения Facebook были сначала извлечены, и только затем я создал бы новый объект Facebook.

Тогда я настоятельно рекомендую вам написать тест, чтобы проверить, выполняется ли ваша функция один раз.Кажется, это выполняется два раза.

И после этого, похоже, возникло состояние гонки после ожидания получения результатов на Facebook.

0 голосов
/ 11 марта 2011

Из Ruby on Rails v3.0.5 Модуль ActiveRecord :: Проверки :: ClassMethods http://s831.us/dK6mFQ

Параллельность и целостность

Использование этого [validates_uniqueness_of] метод проверки в сочетании с ActiveRecord :: Base # сохранить не гарантировать отсутствие дубликата запись вставок, потому что уникальность проверки на уровне приложения по своей природе подвержен гоночным условиям. Например, предположим, что два пользователя попробуйте оставить комментарий в то же время, и заголовок комментария должен быть уникальный. На уровне базы данных действия, выполняемые этими пользователями, могут чередоваться в следующем манера: ...

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