Search code examples
ruby-on-railsrubyormchainedscopes

Rails, how do I chain scopes with an "and" operator between them?


I have a scope that look like this:

scope :attr_similar_to, -> (attr, strings) { where("#{attr} similar to ?", "%(#{strings})%") }

The way I use this scope is that iterate through a number of attributes and for each attribute I send the attribute into the scope along with a set of multiple strings in the 'strings' variable, which gets sent into this scope as "foo|bar|etc". So for each attribute, I check if the attribute value is similar to any of the strings.

The loop where I use this scope looks like this:

results = Model.none
attributes.each do |attr|
  results += attr_similar_to(attr, strings)
end

The problem is that if I have two attributes, "name" and "age", and only "name" matches on "foo", it will still fetch me all those records matching with "foo". I want to be able to chain these scope calls with something like an "and" operator between them so that for example both "name" and "age" must get a match each in order to fetch me any records.

Am I perhaps trying to do this in a wrong or inefficient way?


Solution

  • results = Model.all    # Model.scoped in rails 3
    
    attributes.each do |attr|
      results = results.attr_similar_to(attr, strings)
    end
    

    Or more concise:

    results = attributes.inject(Model.all) do |result, attr| 
      result.attr_similar_to(attr, strings)
    end