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

  #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

      

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?

+3


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)
  end

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

      



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)
    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

      

+2


source







All Articles