检查数组在Rails中是否包含true

时间:2019-02-25 22:18:52

标签: sql ruby-on-rails arrays ruby activerecord

我正在尝试限制每个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 :(得分: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")