问题
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:
"all"— that means, effectively, do not apply this filter, and return articles from all countries (or articles in all languages);- array of id's — that will mean, return articles only from countries with provided id's (or in languages with provided id's)
- empty array — I guess, that is a special case of the previous option; it will mean that articles from no country (or in no language) have to be returned, so no articles will be returned
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"?
回答1:
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.
回答2:
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
回答3:
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
}
来源:https://stackoverflow.com/questions/28989814/rails-chaining-filter-methods-on-a-model