验证数组 Active Record 中的包含时出错

Error while validating inclussion in array Active Record

我在将以下句子翻译到 Rails 范围时遇到了一些问题:

SELECT COUNT(*) FROM permission_activities pa 
JOIN activities a ON pa.activity_id = a.id 
WHERE a.method = :method AND :url ~ a.url_regex AND pa.permission_id IN(:permission_ids)

我带来了类似的东西:

class PermissionActivity < ApplicationRecord
  belongs_to :permission
  belongs_to :activity

  scope :allowed_access, lambda { |permissions, url, method|
    includes(:activity).where(
      'activity.method = :method AND :url LIKE activity.url_regex
      AND permission_activity.permission_id IN :permissions',
      method: method, url: url, permissions: permissions
    )
  }
end

但是我得到这个错误:

ActiveRecord::StatementInvalid (PG::SyntaxError: ERROR:  syntax error at or near "1")
LINE 2:       AND permission_activity.permission_id IN 1,2,3) LIMIT ...

为什么 permissions 没有显示为数组?我错过了一些明显的东西吗?还是我的方法从构思上就注定了?

有用信息:

class Permission < ApplicationRecord
  has_many :permission_activities, dependent: :destroy
  has_many :activities, through: :permission_activities
end

class Activity < ApplicationRecord
  has_many :permission_activities, dependent: :destroy
  has_many :permissions, through: :permission_activities
end

class PermissionActivity < ApplicationRecord
  belongs_to :permission
  belongs_to :activity
end

这里有几个问题:

  1. ~(在原始查询中)适用于正则表达式,LIKE 不适用。
  2. SQL 中的 table 名字应该是复数,而不是像你这样的单数。
  3. 您询问的 IN 问题。

修复第一个很容易:将 LIKE 替换为 ~。固定第二个也很容易:使用复数。修复第三个也很简单:IN 想要一个列表,所以在命名的占位符周围添加一些括号。

应用那些给你:

scope :allowed_access, lambda { |permissions, url, method|
  includes(:activity).where(
    'activities.method = :method AND :url ~ activities.url_regex
    AND permission_activities.permission_id IN (:permissions)',
    method: method, url: url, permissions: permissions
  )
}

大多数查询不需要使用字符串:

class PermissionActivity < ApplicationRecord
  belongs_to :permission
  belongs_to :activity

  def self.allowed_access(permissions, url, method)
    includes(:activity)
    .where("? ~ activities.url_regex", url)
    .where(
       activities: { 
         method: method
       },
       permission_activities: {
         permission_id: permissions
       } 
     })
  end
end

当您链式调用 where 时,它将使用 AND 连接条件,当您传递条件散列时同样适用。

不要对多行方法使用作用域 - 它只是一种被过度使用的用于创建 class 方法的语法糖。该文档非常具有误导性 - 它绝对会下蹲,除了 singleton_class.define_method ... 并在你设法破坏某些东西时加注。按照惯例,它用于声明查询数据库的方法。它使您的代码更难阅读并隐藏静态分析的方法。

如果您确实像创建块一样创建多行 lambda use do ... end instead of braces