Запрос модели Active Record в цикле self выполняется по-разному в рельсах - PullRequest
0 голосов
/ 18 апреля 2019

Я создаю Oauth на Facebook, используя драгоценный камень facebook-omniauth. Я написал этот метод для создания пользователя на основе данных аутентификации.

def self.from_omniauth(auth)
    where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
      user.email = auth.info.email
      user.password = Devise.friendly_token[0, 20]
      user.username =  check_username(auth.info.email)
      user.remote_avatar_url = get_image_url(auth)
      user.skip_confirmation!
    end
  end

и для генерации username я написал этот метод, где он проверяет, присутствует ли данное имя пользователя в данный момент или нет.

def self.check_username(value)
    username = value.split("@").first
    byebug 
    while(User.where(username: username).exists?)
      username += rand(100).to_s
    end
    username
  end

Происходит очень странная ошибка или, может быть, я чего-то не знаю. Вот когда я пытаюсь выполнить User.where(username: username), который должен быть результатом в select * from users where username=username это на самом деле выполняет

User.where(username: username)
  CACHE (0.3ms)  SELECT `users`.* FROM `users` WHERE `users`.`provider` = 'google_oauth2' AND `users`.`uid` = '101977206788010441641' AND `users`.`username` = 'ashjambhulkar'

даже когда я пытаюсь просто извлечь все записи пользователей, которые она выдает

(byebug) User.all
  CACHE (0.0ms)  SELECT `users`.* FROM `users` WHERE `users`.`provider` = 'google_oauth2' AND `users`.`uid` = '101977206788010441641'  [["provider", "google_oauth2"], ["uid", "101977241641"]]
#<ActiveRecord::Relation []>

как я могу изменить этот запрос, чтобы он выполнялся нормально.

1 Ответ

2 голосов
/ 18 апреля 2019

Проблема в том, что вы вызываете этот метод внутри блока first_or_create.

first_or_create буквально означает first || create(*args, &block).Теперь, когда create вызывается с блоком, все запросы внутри этого блока попадают в текущую область с помощью метода, называемого scoping

Состояние документов: «Область действия всех запросовв текущую область ... Пожалуйста, отметьте unscoped, если вы хотите удалить все предыдущие области (включая default_scope) во время выполнения блока.

С примером:

Comment.where(post_id: 1).scoping do
  Comment.first
end
=> SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = 1 ORDER BY "comments"."id" ASC LIMIT 1

Вы должны быть в состоянии решить эту проблему с помощью

def self.check_username(value)
  username = value.split("@").first
  while(User.unscoped.where(username: username).exists?)
    username += rand(100).to_s
  end
  username
end
...