1

I have two models

class Filters < ActiveRecord::Base
end

class Groups < ActiveRecord::Base
end

Filter model is responsible for fetching user data from db e.g

filter_id_1. SELECT users.* FROM users INNER JOIN notes ON notes.user_id = users.id WHERE notes.category = 'Emotions'

filter_id_2. SELECT users.* FROM users INNER JOIN subscriptions ON subscriptions.user_id = users.id WHERE (Date(end_date) = CURDATE())

filter_id_3. SELECT users.* FROM users WHERE (auth_token_created_at > DATE_SUB(NOW(), INTERVAL 2 hour))

Group model makes a group with multiple filters with AND and OR conditions e.g

group_id_1 = "filter_id_1 AND filter_id_2 OR filter_id_3"

Now using group I am trying to fetch users by converting expression to methods according to AND OR conditions.

users = Filter.find(1).get_users &  Filter.find(2).get_users | Filter.find(3).get_users

How can i convert this experssion from this "filter_id_1 AND filter_id_2 OR filter_id_3"

to this

users = Filter.find(1).get_users & Filter.find(2).get_users | Filter.find(3).get_users

Bloomberg
  • 2,317
  • 2
  • 25
  • 47

2 Answers2

0

If you can, you might want to convert your group format to something more structured, like [1, '&', 2, '|', 3], which will make it easier to apply. If not, we can get there pretty quickly with some simple substitutions:

parts = 'filter_id_1 AND filter_id_2 OR filter_id_3'
  .gsub('filter_id_', '')
  .gsub('AND', '&')
  .gsub('OR', '|')
  .split
#=> ["1", "&", "2", "|", "3"]

Then you can construct your list of users by walking through the symbols:

parts = ["1", "&", "2", "|", "3"]
users = Filter.find(parts.shift).get_users
while parts.any?
  op = parts.shift
  next_users = Filter.find(parts.shift).get_users
  users = users.send(op, next_users)
end

As long as there's something left in parts (and assuming the group was well formed), you know there's an operation followed by another filter ID. Grabbing each of those, you can send the op to your existing users to apply the next set of users in the right way.

Kristján
  • 18,165
  • 5
  • 50
  • 62
0

A better solution for your purpose I think is that using scope in User model and query methods.

Query Methods

In rails, ActiveRecord offers lots of query methods to implement that, like this:

User.joins(:notes).where(notes: {category: 'Emotions'})

This produces:

SELECT users.* FROM users INNER JOIN notes ON notes.user_id = users.id WHERE notes.category = 'Emotions'

ref: http://guides.rubyonrails.org/active_record_querying.html

Scope

#app/models/user.rb
class User
  scope :group_by_note_category -> (category){
    self.joins(:notes).where(notes: {category: category})
  }
end

#use like this
User.group_by_note_category('Emotions')

Your purpose is that combine two Active:Relation objects using 'And' and 'Or'. Hoping this would be of use.

ref: Combine two ActiveRecord::Relation objects

Community
  • 1
  • 1
Eason Caizhen Liu
  • 459
  • 1
  • 5
  • 12
  • I agree with you ActiveRecord Query would be an awesome solution. But Scopes can be used when you know what exact relation you have to define b/w filters. These filters will be generated on the fly by users. It could be any thing like: "filter_1 AND filter_2" or lets say "filter_2 AND filter_4 AND filter_6". here I dont know user will define what exact combination b/w filters. – Bloomberg Apr 27 '16 at 16:35