Rails: storing filter conditions by attributes and checking if the conditions pass?

I have a SaaS application where the account has many users.

In the account, the account owner can specify specific filters for users who apply to participate in the account. For example, it can specify that these requirement conditions must be met in order for a user to be considered: user.age> 21, user.name.count> 4.

I was thinking about creating a FilterCondition model that belongs to an account where the line could look like account_id: 1, attribute: "age", condition_string: "> 21"

oraccount_id: 1, attribute: "phone_type", condition_string: "== iphone"

and then when I only want to accept users meeting those conditions, do something like

  def passes_requirements?
    account.filter_conditions.each do |filter_conditions|
      attr = filter_condition.attribute
      return false if self.attr != filter_condition.condition


I know this is completely wrong syntax, but he should figure out what I would like to do.

Any suggested ways to allow accounts to save the requirement terms and then check against Users to see if they meet the requirement?


source to share

1 answer

It will be easier if the condition string is split into a comparator (for example >

) and a comparable value:

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)

  def safe_comparator
    safe_values = ['=', '>', '>=', '<', '<='] # etc
    return comparator if safe_values.include? comparator


The method safe_comparator

reduces the risk of SQL injection into the query. The filter collection chaining is a bit tricky, but something like the following idea should work.

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)


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





All Articles