azangru
azangru

Reputation: 2738

Rails: Chaining filter methods on a model

My web app is showing a list of articles. Articles can be published in different countries (i.e. Article belongs to a Country, and Country has many Articles), and in different languages (i.e. Article belongs to a Language, and Language has many Articles).

What I would like to do is to make requests that will return me articles from selected countries and in selected languages. That is, I would eventually like to make a request such as this:

Article.selected_countries.selected_languages

and get a list of articles.

Both for the countries, and for the languages, the front-end can send the following parameters:

Now, what confuses me is to how to write these class methods and how to make them chainable. Rails Guides provide the following example:

class Article < ActiveRecord::Base
  def self.created_before(time)
    where("created_at < ?", time)
  end
end

if I build a class method based on this example, such as the following:

def self.selected_countries(parameter)
  ???
end

How do I define this method provided the parameter can be the string "all", an array of id's, or an empty array? Also, how do I make sure the filter doesn't do anything if the parameter is "all"?

Upvotes: 1

Views: 1352

Answers (3)

messanjah
messanjah

Reputation: 9278

def self.selected_countries(parameters)
  case parameters
  when "all"
    all
  else
    where(country_id: parameters)
  end
end

Subsequent chains of scope methods append to the query, instead of replacing it.

So you could call this scope like

Article.selected_countries([1]).selected_countries("all")

and you'll get all the Articles for country 1.

Upvotes: 2

Chris Bushell
Chris Bushell

Reputation: 1095

Rails has built in support for what you're trying to achieve in the form of "scopes". You'll find everything you need to know in RailsGuides.

http://guides.rubyonrails.org/active_record_querying.html#scopes

Upvotes: 3

Albin
Albin

Reputation: 3012

What you are describing is called scopes in rails. http://guides.rubyonrails.org/active_record_querying.html#scopes

The nice thing about scopes is that (if written right) they support exactly the kind of chaining you want. Here is an example of a scope, it returns all if given an empty array otherwise it returns records associated with any of the countries in the array:

scope : selected_countries, lambda { |countries|
  if countries.length == 0
    all
  else
    where(country_id: countries)
  end
}

Upvotes: 3

Related Questions