Проверьте, содержит ли Array значение true в Rails - PullRequest
0 голосов
/ 26 февраля 2019

Я пытаюсь ограничить число неудачных попыток входа в систему для ip.

У меня есть следующее:

  def validate(email, context)
    attempt = insert_into_attempts(email, context)
    return nil unless allow_login_by_ip(context.ip_address)
    flag_successful_attempt(attempt, context.ip_address)
    load_data
  end

  def allow_login_by_ip(ip_address)
    limit = LoginLimits.new(ip_address).limit
    last_5_attempts = AuthenticationAttempt.select("id","successful").where(ip: ip_address).last(5)
    last_5_attempts.include?("true")
  end 

  def insert_into_attempts(email, context)
    attempt = AuthenticationAttempt.new(
      :email => email,
      :ip => context.ip_address)
    attempt.save
  end 

  def flag_successful_attempt(attempt, ip_address)
    AuthenticationAttempt.where(ip: ip_address).last.update(successful: '1')
  end

Проблема, с которой я сталкиваюсь, заключается в том, что она всегда возвращает fasle.Я должен искать array неправильно, но я не уверен, почему.last_5_attempts это:

#<AuthenticationAttempt id: 1, successful: false>, 
#<AuthenticationAttempt id: 2, successful: false>, 
#<AuthenticationAttempt id: 3, successful: true>,
#<AuthenticationAttempt id: 4, successful: false>, 
#<AuthenticationAttempt id: 5, successful: false>]

Ответы [ 3 ]

0 голосов
/ 26 февраля 2019
AuthenticationAttempt.where(ip: ip_address)<del>.last(5)</del>.exists?(successful: true)
<del>AuthenticationAttempt.where(ip: ip_address).order(id: :desc).limit(5).exists?(successful: true)</del>

Вы можете использовать ActiveRecord :: FinderMethods # существующие? для проверки успешной попытки без извлечения каких-либо данных или создания каких-либо записей.

Обновление: нам нужно использовать .order(id: :desc).limit(5) вместо .last(5), чтобы убедиться, что у нас есть экземпляр ActiveRecord :: Relation для вызова exists?.

Update2 : exists? заменяет любой limit, заданный на limit(1)

AuthenticationAttempt.limit(5).exists?
=> SELECT 1 AS one FROM "authentication_attempts" LIMIT $1  [["LIMIT", 1]]

Поэтому нам нужно заключить подзапрос в запрос внешнего существования:

AuthenticationAttempt.exists?(AuthenticationAttempt.limit(5))
=> SELECT  1 AS one FROM "authentication_attmepts" WHERE "authentication_attmepts"."id" IN (SELECT  "authentication_attmepts"."id" FROM "authentication_attmepts" LIMIT $1) LIMIT $2  [["LIMIT", 5], ["LIMIT", 1]]

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

 AuthenticationAttempt
   .where(successful: true)
   .exists?(AuthenticationAttempt.where(ip: ip_address).order(id: :desc).limit(5))
0 голосов
/ 26 февраля 2019

попробуйте

last_5_attempts.map(&:to_s).include?("true")

вместо

last_5_attempts.include?("true")
0 голосов
/ 26 февраля 2019

Если вы имеете в виду true, то вы имеете в виду:

last_5_attempts.include?(true)

Потому что:

true == "true"
# => false

Но этого недостаточно, поскольку вы спрашиваете, является ли массив *В 1008 * значениях есть любая запись, которая буквально просто true, ([1,true] != true), поэтому вы хотите:

last_5_attempts.any? |id, successful|
  successful
end

Вы также можете опустить id в выборке столбца, посколькувы не используете его и вместо этого:

AuthenticationAttempt.where(ip: ip_address).pluck(:successful).last(5).any?

Где pluck с одним аргументом возвращает «плоский» массив вместо массива массивов.

Чтобы проверить по крайней мереодин успешный вход в систему за последние 5 или отсутствие истории входа:

attempts = AuthenticationAttempt.where(ip: ip_address)
!attempts.any? or attempts.pluck(:successful).last(5).any?
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...