我正在尝试限制每个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>]
答案 0 :(得分:3)
如果您的意思是/** Key code constant: Sleep key.
* Puts the device to sleep. Behaves somewhat like {@link #KEYCODE_POWER} but it
* has no effect if the device is already asleep. */
public static final int KEYCODE_SLEEP = 223;
/** Key code constant: Wakeup key.
* Wakes up the device. Behaves somewhat like {@link #KEYCODE_POWER} but it
* has no effect if the device is already awake. */
public static final int KEYCODE_WAKEUP = 224;
,那么您的意思是:
true
因为:
last_5_attempts.include?(true)
但这还不够,因为您要询问true == "true"
# => false
值数组是否具有字面只是[id, successful]
,({{1 ),所以您想要:
true
您也可以从列获取中省略[1,true] != true
,因为您不使用它,而是:
last_5_attempts.any? |id, successful|
successful
end
id
仅带有一个参数的地方返回一个“平面”数组,而不是数组数组。
要检查最近5次或没有登录历史中至少有一次成功登录:
AuthenticationAttempt.where(ip: ip_address).pluck(:successful).last(5).any?
答案 1 :(得分:1)
AuthenticationAttempt.where(ip: ip_address).last(5).exists?(successful: true)
AuthenticationAttempt.where(ip: ip_address).order(id: :desc).limit(5).exists?(successful: true)
您可以使用ActiveRecord::FinderMethods#exists?来检查是否成功尝试,而无需检索任何数据或实例化任何记录。
更新:我们需要使用.order(id: :desc).limit(5)
代替.last(5)
,以确保我们有一个ActiveRecord::Relation实例可以调用exists?
。< / p>
更新2 :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]]
这是一个稍微复杂的查询,但是仍然具有不从数据库中加载任何内容的性能优势。内部子查询为我们提供了最后5次尝试,外部查询检查了是否存在成功尝试:
AuthenticationAttempt
.where(successful: true)
.exists?(AuthenticationAttempt.where(ip: ip_address).order(id: :desc).limit(5))
答案 2 :(得分:1)
尝试
last_5_attempts.map(&:to_s).include?("true")
代替
last_5_attempts.include?("true")