Sql Rails:保存属性上的筛选条件并检查条件是否通过?
我有一个SaaS应用程序,其中一个帐户有许多用户 在帐户中,帐户所有者可以对申请成为帐户一部分的用户指定某些筛选器。例如,他可以设置必须满足这些要求条件才能接受用户:user.age>21,user.name.count>4 我正在考虑创建一个FilterCondition模型,它属于Account,其中一行可以看起来像Sql Rails:保存属性上的筛选条件并检查条件是否通过?,sql,ruby-on-rails,ruby,ruby-on-rails-4,filter,Sql,Ruby On Rails,Ruby,Ruby On Rails 4,Filter,我有一个SaaS应用程序,其中一个帐户有许多用户 在帐户中,帐户所有者可以对申请成为帐户一部分的用户指定某些筛选器。例如,他可以设置必须满足这些要求条件才能接受用户:user.age>21,user.name.count>4 我正在考虑创建一个FilterCondition模型,它属于Account,其中一行可以看起来像Account\u id:1,属性:“年龄”,条件字符串:“>21”或Account\u id:1,属性:“电话类型”,条件字符串:==iphone” 然后,当我只想接受满足这些
Account\u id:1,属性:“年龄”,条件字符串:“>21”
或Account\u id:1,属性:“电话类型”,条件字符串:==iphone”
然后,当我只想接受满足这些条件的用户时,请执行以下操作
#User.rb
def passes_requirements?
account.filter_conditions.each do |filter_conditions|
attr = filter_condition.attribute
return false if self.attr != filter_condition.condition
end
true
end
我知道这是完全错误的语法,但它应该让我明白我想做什么
允许帐户保存需求条件,然后检查用户是否满足这些要求的任何建议方法?如果将条件字符串分为一个比较器(例如
)和要比较的值,会更容易:
class FilterCondition < ActiveRecord::Base
belongs_to :account
validates :attribute, presence: true
validates :comparator, presence: true
validates :value, presence: true
def matching_users(query_chain = User.where(account: account))
query_chain.where("#{attribute} #{safe_comparator} ?", value)
end
private
def safe_comparator
safe_values = ['=', '>', '>=', '<', '<='] # etc
return comparator if safe_values.include? comparator
''
end
end
如果我们也要比较字符串,这会起作用吗?就像“用户电话类型必须是iPhone或Android”,只要
FilterCondition
中value
的DB type是字符串,它就会过滤掉使用其他电话的用户。生成的ActiveRecord查询将是where(“phone\u type=?,'iPhone')
。执行OR查询(例如Android或iPhone)比较困难,需要重构FilterCondition
(但并非不可能)查询链。它仍然是字符串类型。我们有没有办法做#{safe_comparator.to_comparator}之类的事情?它应该是一个字符串。实际上,您发送的是一个Arel/ActiveRecord查询字符串以及一组值。然后以sql安全的方式将问号替换为值,并将整个字符串转换为sql查询。这就是我们最终提出的解决方案:
class Account < ActiveRecord::Base
#....
has_many :filter_conditions
def filtered_users
query = User.where(account: self)
filter_conditions.each do |filter_condition|
query = filter_condition.matching_users(query)
end
query
end
end
account = Account.first
filter_1 = FilterCondition.create(
account: account,
attribute: :age,
comparator: '>=',
value: 21
)
filter_2 = FilterCondition.create(
account: account,
attribute: :age,
comparator: '<=',
value: 99
)
account.filtered_users