Filterrific and Globalize - ruby-on-rails

It appears as if filterrific does not take content in translation tables into account (Globalize).
Is there anyway to search translation tables as well? My setup works perfectly well if the content is in the actual model. However, once the fields are empty and only entered in the translation table no results are being displayed (obviously).
My Model:
class Manual < ApplicationRecord
translates :title, :content, :teaser, :slug
extend FriendlyId
friendly_id :title, :use => :globalize
belongs_to :user
belongs_to :support_category
has_many :manual_faqs
has_many :faqs, :through => :manual_faqs
validates :title, presence: true
validates :content, presence: true
validates :user_id, presence: true
update_index('manuals#manual') { self }
filterrific(
default_filter_params: { sorted_by: 'created_at_desc' },
available_filters: [
:sorted_by,
:search_query,
:with_user_id,
:with_created_at_gte
]
)
scope :with_user_id, lambda { |user_ids|
where(user_id: [*user_ids])
}
scope :search_query, lambda { |query|
# Searches the students table on the 'first_name' and 'last_name' columns.
# Matches using LIKE, automatically appends '%' to each term.
# LIKE is case INsensitive with MySQL, however it is case
# sensitive with PostGreSQL. To make it work in both worlds,
# we downcase everything.
return nil if query.blank?
# condition query, parse into individual keywords
terms = query.downcase.split(/\s+/)
# replace "*" with "%" for wildcard searches,
# append '%', remove duplicate '%'s
terms = terms.map { |e|
('%' + e.gsub('*', '%') + '%').gsub(/%+/, '%')
}
# configure number of OR conditions for provision
# of interpolation arguments. Adjust this if you
# change the number of OR conditions.
num_or_conds = 2
where(
terms.map { |term|
"(LOWER(manuals.title) LIKE ? OR LOWER(manuals.content) LIKE ?)"
}.join(' AND '),
*terms.map { |e| [e] * num_or_conds }.flatten
)
}
scope :sorted_by, lambda { |sort_option|
# extract the sort direction from the param value.
direction = (sort_option =~ /desc$/) ? 'desc' : 'asc'
case sort_option.to_s
when /^created_at_/
# Simple sort on the created_at column.
# Make sure to include the table name to avoid ambiguous column names.
# Joining on other tables is quite common in Filterrific, and almost
# every ActiveRecord table has a 'created_at' column.
order("manuals.created_at #{ direction }")
else
raise(ArgumentError, "Invalid sort option: #{ sort_option.inspect }")
end
}
scope :created_at_gte, lambda { |reference_time|
where('manuals.created_at >= ?', reference_time)
}
def self.options_for_sorted_by
[
['Date received (newest first)', 'created_at_desc'],
['Date received (oldest first)', 'created_at_asc']
]
end
end
My Controller:
def index
#filterrific = initialize_filterrific(
Manual,
params[:filterrific],
select_options: {
sorted_by: Manual.options_for_sorted_by,
with_user_id: User.options_for_select
}
) or return
#manuals = #filterrific.find.page(params[:page])
respond_to do |format|
format.html
format.js
end
rescue ActiveRecord::RecordNotFound => e
# There is an issue with the persisted param_set. Reset it.
puts "Had to reset filterrific params: #{ e.message }"
redirect_to(reset_filterrific_url(format: :html)) and return
#respond_with(#references)
end

I don't know filterrific at all but I do know Globalize, and since filterrific is based on AR scopes it should be simply a matter of joining the translation table to get results to show up.
Here's your search_query scope modified to join and search the joined translations table (without the comments for clarity):
scope :search_query, lambda { |query|
return nil if query.blank?
terms = query.downcase.split(/\s+/)
terms = terms.map { |e|
('%' + e.gsub('*', '%') + '%').gsub(/%+/, '%')
}
num_or_conds = 2
where(
('(LOWER(manual_translations.title) LIKE ? OR'\
' LOWER(manual_translations.content) LIKE ?)' * (terms.count)).join(' AND '),
*terms.map { |e| [e] * num_or_conds }.flatten
).with_translations
}
Notice I've only changed two things: (1) I've appended with_translations, a method described in this SO answer which joins the translations for the current locale, and (2) I've swapped the manuals table for the manual_translations table in the query.
So if you call this query in the English locale:
Manual.search_query("foo")
you get this SQL:
SELECT "manuals".* FROM "manuals"
INNER JOIN "manual_translations" ON "manual_translations"."manual_id" = "manuals"."id"
WHERE (LOWER(manual_translations.title) LIKE '%foo%' OR
LOWER(manual_translations.content) LIKE '%foo%')
AND "manual_translations"."locale" = 'en'"
Notice that with_translations is automatically tagging on that manual_translations.locale = 'en' so you filter out only results in your locale, which I assume is what you want.
Let me know if that works for you.

Related

Rails- Building dynamic query for filtering search results

I am trying to build a dynamic querying method to filter search results.
My models:
class Order < ActiveRecord::Base
scope :by_state, -> (state) { joins(:states).where("states.id = ?", state) }
scope :by_counsel, -> (counsel) { where("counsel_id = ?", counsel) }
scope :by_sales_rep, -> (sales) { where("sales_id = ?", sales) }
scope :by_year, -> (year) { where("title_number LIKE ?", "%NYN#{year}%") }
has_many :properties, :dependent => :destroy
has_many :documents, :dependent => :destroy
has_many :participants, :dependent => :destroy
has_many :states, through: :properties
belongs_to :action
belongs_to :role
belongs_to :type
belongs_to :sales, :class_name => 'Member'
belongs_to :counsel, :class_name => 'Member'
belongs_to :deal_name
end
class Property < ActiveRecord::Base
belongs_to :order
belongs_to :state
end
class State < ActiveRecord::Base
has_many :properties
has_many :orders, through: :properties
end
I have a page where I display ALL orders by default. I want to have check boxes to allow for filtering of the results. The filters are: Year, State, Sales, and Counsel. an example of a query is: All orders in 2016, 2015("order.title_number LIKE ?", "%NYN#{year}%") in states (has_many through) NJ, PA, CA, etc with sales_id unlimited ids and counsel_id unlimited counsel_ids.
In a nut shell I am trying to figure out how to create ONE query that takes into account ALL options the user checks. Here is my current query code:
def Order.query(opt = {})
results = []
orders = []
if !opt["state"].empty?
opt["state"].each do |value|
if orders.empty?
orders = Order.send("by_state", value)
else
orders << Order.send("by_state", value)
end
end
orders = orders.flatten
end
if !opt["year"].empty?
new_orders = []
opt["year"].each do |y|
new_orders = orders.by_year(y)
results << new_orders
end
end
if !opt["sales_id"].empty?
end
if !opt["counsel_id"].empty?
end
if !results.empty?
results.flatten
else
orders.flatten
end
end
Here is the solution I have come up with to allow for unlimited amount of filtering.
def self.query(opts = {})
orders = Order.all
opts.delete_if { |key, value| value.blank? }
const_query = ""
state_query = nil
counsel_query = nil
sales_query = nil
year_query = nil
queries = []
if opts["by_year"]
year_query = opts["by_year"].map do |val|
" title_number LIKE '%NYN#{val}%' "
end.join(" or ")
queries << year_query
end
if opts["by_sales_rep"]
sales_query = opts["by_sales_rep"].map do |val|
" sales_id = '#{val}' "
end.join(" or ")
queries << sales_query
end
if opts["by_counsel"]
counsel_query = opts["by_counsel"].map do |val|
" counsel_id = '#{val}' "
end.join(" or ")
queries << counsel_query
end
if opts["by_state"]
state_query = opts["by_state"].map do |val|
"states.id = '#{val}'"
end.join(" or ")
end
query_string = queries.join(" AND ")
if state_query
#orders = Order.joins(:states).where("#{state_query}")
#orders = #orders.where(query_string)
else
#orders = orders.where("#{query_string}")
end
#orders.order("title_number DESC")
end
What you're looking for a query/filter object, which is a common pattern. I wrote an answer similar to this, but I'll try to extract the important parts.
First you should move those logic to it's own object. When the search/filter object is initialized it should start with a relation query (Order.all or some base query) and then filter that as you go.
Here is a super basic example that isn't fleshed out but should get you on the right track. You would call it like so, orders = OrderQuery.call(params).
# /app/services/order_query.rb
class OrderQuery
def call(opts)
new(opts).results
end
private
attr_reader :opts, :orders
def new(opts={})
#opts = opts
#orders = Order.all # If using Rails 3 you'll need to use something like
# Order.where(1=1) to get a Relation instead of an Array.
end
def results
if !opt['state'].empty?
opt['state'].each do |state|
#orders = orders.by_state(state)
end
end
if !opt['year'].empty?
opt['year'].each do |year|
#orders = orders.by_year(year)
end
end
# ... all filtering logic
# you could also put this in private functions for each
# type of filter you support.
orders
end
end
EDIT: Using OR logic instead of AND logic
# /app/services/order_query.rb
class OrderQuery
def call(opts)
new(opts).results
end
private
attr_reader :opts, :orders
def new(opts={})
#opts = opts
#orders = Order.all # If using Rails 3 you'll need to use something like
# Order.where(1=1) to get a Relation instead of an Array.
end
def results
if !opt['state'].empty?
#orders = orders.where(state: opt['state'])
end
if !opt['year'].empty?
#orders = orders.where(year: opt['year'])
end
# ... all filtering logic
# you could also put this in private functions for each
# type of filter you support.
orders
end
end
The above syntax basically filters sayings if state is in this array of states and year is within this array of years.
In my case, the filter options came from the Controller's params, so I've done something like this:
The ActionController::Parameters structure:
{
all: <Can be true or false>,
has_planned_tasks: <Can be true or false>
... future filters params
}
The filter method:
def self.filter(filter_params)
filter_params.reduce(all) do |queries, filter_pair|
filter_key = filter_pair[0]
filter_value = filter_pair[1]
return {
all: proc { queries.where(deleted_at: nil) if filter_value == false },
has_planned_tasks: proc { queries.joins(:planned_tasks).distinct if filter_value == true },
}.fetch(filter_key).call || queries
end
end
Then I call the ModelName.filter(filter_params.to_h) in the Controller. I was able to add more conditional filters easily doing like this.
There's space for improving here, like extract the filters logic or the whole filter object, but I let you decide what is better in your context.
Here is one I built for an ecommerce order dashboard in Rails with the parameters coming from the controller.
This query will execute twice, once to count the orders and once to return the requested orders according to the parameters in the request.
This query supports:
Sort by column
Sort direction
Incremental Search - It'll search the beginning of a given field and returns those records that match enabling real-time suggestions while searching
Pagination (limited by 100 records per page)
I also have predefined values to sanitize some of the data.
This style is extremely clean and easy for others to read and modify.
Here's a sample query:
api/shipping/orders?pageNumber=1&orderStatus=unprocessedOrders&filters=standard,second_day&stores=82891&sort_column=Date&sort_direction=dsc&search_query=916
And here's the controller code:
user_id = session_user.id
order_status = params[:orderStatus]
status = {
"unprocessedOrders" => ["0", "1", "4", "5"],
"processedOrders" => ["2", "3", "6"],
"printedOrders" => ["3"],
"ratedOrders" => ["1"],
}
services = [
"standard",
"expedited",
"next_day",
"second_day"
]
countries = [
"domestic",
"international"
]
country_defs = {
domestic: ['US'],
international: ['CA', 'AE', 'EU', 'GB', 'MX', 'FR']
}
columns = {
Number: "order_number",
QTY: "order_qty",
Weight: "weight",
Status: "order_status",
Date: "order_date",
Carrier: "ship_with_carrier",
Service: "ship_with_carrier_code",
Shipping: "requestedShippingService",
Rate: "cheapest_rate",
Domestic: "country",
Batch: "print_batch_id",
Skus: "skus"
}
# sort_column=${sortColumn}&sort_direction=${sortDirection}&search_query=${searchQuery}
filters = params[:filters].split(',')
stores = params[:stores].split(',')
sort_column = params[:sort_column]
sort_direction = params[:sort_direction]
search_query = params[:search_query]
sort_by_column = columns[params[:sort_column].to_sym]
sort_direction = params[:sort_direction] == "asc" ? "asc" : "desc"
service_params = filters.select{ |p| services.include?(p) }
country_params = filters.select{ |p| countries.include?(p) }
order_status_params = filters.select{ |p| status[p] != nil }
query_countries = []
query_countries << country_defs[:"#{country_params[0]}"] if country_params[0]
query_countries << country_defs[:"#{country_params[1]}"] if country_params[1]
active_filters = [service_params, country_params].flatten
query = Order.where(user_id: user_id)
query = query.where(order_status: status[order_status]) if order_status_params.empty?
query = query.where("order_number ILIKE ? OR order_id::TEXT ILIKE ? OR order_info->'advancedOptions'->>'customField2' ILIKE ?", "%#{search_query}%", "%#{search_query}%", "%#{search_query}%") unless search_query.gsub(/\s+/, "").length == 0
query = query.where(requestedShippingService: service_params) unless service_params.empty?
query = query.where(country: "US") if country_params.include?("domestic") && !country_params.include?("international")
query = query.where.not(country: "US") if country_params.include?("international") && !country_params.include?("domestic")
query = query.where(order_status: status[order_status_params[0]]) unless order_status_params.empty?
query = query.where(store_id: stores) unless stores.empty?\
order_count = query.count
num_of_pages = (order_count.to_f / 100).ceil()
requested_page = params[:pageNumber].to_i
formatted_number = (requested_page.to_s + "00").to_i
query = query.offset(formatted_number - 100) unless requested_page == 1
query = query.limit(100)
query = query.order("#{sort_by_column}": :"#{sort_direction}") unless sort_by_column == "skus"
query = query.order("skus[1] #{sort_direction}") if sort_by_column == "skus"
query = query.order(order_number: :"#{sort_direction}")
orders = query.all
puts "After querying orders mem:" + mem.mb.to_s
requested_page = requested_page <= num_of_pages ? requested_page : 1
options = {}
options[:meta] = {
page_number: requested_page,
pages: num_of_pages,
type: order_status,
count: order_count,
active_filters: active_filters
}
render json: OrderSerializer.new(orders, options).serialized_json

Jbuilder not wrapping single object in collection

I have a index view in my rails application that allows filtering via search params. When a group op articles are returned its is wropped in an articles colllection like {"articles":[{"article":{"id":341,"updated":"2015-08-18T13:05:08.427Z","title":". But if only a single object is found the articles level is missing, {"article":{"id":398,"updated":"2015-08-07T11:37:26.200Z","title":. How can I fix it so that a single object behaves like multiple?
_articles.list.json.jbuilder
require 'uri'
require 'publish_on'
json.cache! ['v1', articles] do
json.articles articles do |article|
json.cache! ['v1', article] do
json.article do
json.id article.id
json.updated as_ns_date(article.updated_at)
json.title article.label
json.numberOfViews article.view_mappings.count
json.numberOfFavorites article.favorite_mappings.count
json.imageURLs article.images if article.images.any?
json.youtubeURL article.youtube unless article.youtube.blank?
json.tags article.categories.map(&:label)
json.isFeatured article.featured
json.isPublished article.is_published
json.published as_ns_date(article.publish_on)
end
end
end
end
index.json.jbuilder
json.partial! 'articles/articles_list', articles: #articles
articles_controller.rb
def index
#articles = SearchArticlesCommand.new(params).execute
render :index
end
search_articles_command.rb
class SearchArticlesCommand
def initialize(params = {})
#since = params[:since_date]
#keys = params[:search_query]
#category = params[:category]
end
def execute
Article.unscoped do
query = if #since.present?
Article.article.since_date(#since)
else
Article.published_article
end
query = query.search_by_keywords(#keys) if #keys.present?
query = query.search_by_category(#category) if #category.present?
query.select(:id, :updated_at, :label, :is_published, :featured, :slug, :created_at).order(created_at: :desc)
end
end
end
article.rb
class Article < Comfy::Cms::Page
include PgSearch
include ActionView::Helpers::SanitizeHelper
HOSTNAME = ENV['HOSTNAME'] || Socket.gethostname
has_many :view_mappings, dependent: :destroy
has_many :favorite_mappings, dependent: :destroy
pg_search_scope :search_by_keywords, against: [:content_cache, :label], using: { tsearch: { any_word: true, prefix: true } }
pg_search_scope :search_by_category, associated_against: {
categories: [:label]
}
scope :since_date, -> (date) { where('created_at > ? OR updated_at > ? ', date, date) if date.present? }
scope :folder, -> { where.not(layout_id: ENV['ARTICLE_LAYOUT_ID']) }
scope :published_article, -> { published.article }
scope :article, -> { where(layout_id: ENV['ARTICLE_LAYOUT_ID']) }
It is what i suspected. If you want the same behavior your query should return the same type of object when it finds one or many articles. The problem is that either you are returning an ActiveRecordRelation or a Article object depending on your params.
#articles = Article.all # => ActiveRecordRelation, an array per se
#articles = Article.find(1) # => Article object
When it comes to jbuilder to construct the JSON it checks if it is an array of objects and then wrap the json with a { keyword => array }. WHen it is a single object, it defaults to a single object {article: {}}.
The solution is simple, you can tweak your SearchArticlesCommand to always return an ActiveRecordRelation, even if it finds only one object.

ActiveRecord build dynamic query conditions

I have a piece of code that seems to work. I just think there may be a much better way to achieve the desired work. The problem is to build an ActiveRecord query with an unknown list of parameters.
Here is the code:
query_string = String.new
query_values = []
unless params[:organization][:name].blank?
query_string << 'name = ?'
query_values << params[:organization][:name]
end
unless params[:organization][:national_id].blank? && params[:organization][:vat_id].blank?
raise RequestParamsException.new('National ID or Vat ID given without country') if params[:organization][:country].nil?
country_id = Country.find_by_name(params[:organization][:country]).pluck(:id)
unless params[:organization][:national_id].blank?
query_string << ' OR ' unless query_string.empty?
query_string << '(national_id = ?'
query_values << params[:organization][:national_id]
query_string << ' AND ' << 'country_id = ?)'
query_values << country_id
end
unless params[:organization][:vat_id].blank?
query_string << ' OR ' unless query_string.empty?
query_string << '(vat_id = ?'
query_values << params[:organization][:vat_id]
query_string << ' AND ' << 'country_id = ?)'
query_values << country_id
end
end
known_organizations = query_string.blank? ? [] : Organization.where(query_string, query_values).uniq
Country is needed when a Vat or National Id are given since these are scoped in the model:
class Organization < ActiveRecord::Base
#======================VALIDATIONS=========================
validates :national_id, :uniqueness => { :scope => :country_id }, :allow_blank => true
validates :vat_id, :uniqueness => { :scope => :country_id }, :allow_blank => true
validates :country, :presence => true
end
You can take advantage of Arel. For example when you write:
posts = Post.where(author_id: 12)
this query isn't executed unless you start iterating on posts or call posts.all. So you can write something like this:
def search_posts
posts = Post.where(active: true)
posts = posts.where('body ilike ?', "%#{params[:query]%") unless params[:query].blank?
posts
end
This simple example shows how to achieve behavior you are looking for.

Spree search filter for properties and variants

I'm running Spree 1.3.1 and I'm trying to customize the Taxon show page.
I would like it to return the products contained inside the current Taxon, eventually filtered by a property or by an option value.
For example let's say that I'm seeing the Taxon of an underwear collection.
I'd like to filter the products shown, by providing a certain size (option_type).
In this case I should list only products that have variants with the requested size.
I would like also to be able to filter the products by the "fit" property.
Filtering by the slip fit, I should be able to list only products inside the current Taxon that have the required property.
This is the Taxon controller show action:
Spree::TaxonsController.class_eval do
def show
#taxon = Spree::Taxon.find_by_permalink!(params[:id])
return unless #taxon
#searcher = Spree::Config.searcher_class.new(params)
#searcher.current_user = try_spree_current_user
#searcher.current_currency = current_currency
#products = #searcher.retrieve_products
respond_with(#taxon)
end
end
How should I modify it to fit my needs?
I partially solved the question.
I found out that I need to leave the controller as it is, the magic is done in the lib/spree/product_filters.rb file where I added this new product filter:
if Spree::Property.table_exists?
Spree::Product.add_search_scope :fit_any do |*opts|
conds = opts.map {|o| ProductFilters.fit_filter[:conds][o]}.reject {|c| c.nil?}
scope = conds.shift
conds.each do |new_scope|
scope = scope.or(new_scope)
end
Spree::Product.with_property("fit").where(scope)
end
def ProductFilters.fit_filter
fit_property = Spree::Property.find_by_name("fit")
fits = Spree::ProductProperty.where(:property_id => fit_property).pluck(:value).uniq
pp = Spree::ProductProperty.arel_table
conds = Hash[*fits.map { |b| [b, pp[:value].eq(b)] }.flatten]
{ :name => "Fits",
:scope => :fit_any,
:conds => conds,
:labels => (fits.sort).map { |k| [k, k] }
}
end
end
Then I added the new filter to the Taxon model decorator with this:
Spree::Taxon.class_eval do
def applicable_filters
fs = []
fs << Spree::Core::ProductFilters.fit_filter if Spree::Core::ProductFilters.respond_to?(:fit_filter)
fs
end
end
Still I haven't found out how to create a filter for variants that have a specific option value.
You talk about filtering on numerical value, I've written a filter for option ranges:
def ProductFilters.ov_range_test(range1, range2)
ov = Arel::Table.new("spree_option_values")
cast = Arel::Nodes::NamedFunction.new "CAST", [ ov[:presentation].as("integer")]
comparaisons = cast.in(range1..range2)
comparaisons
end
Spree::Product.add_search_scope :screenSize_range_any do |*opts|
conds = opts.map {|o| Spree::ProductFilters.screenSize_filter[:conds][o]}.reject {|c| c.nil?}
scope = conds.shift
conds.each do |new_scope|
scope = scope.or(new_scope)
end
option_values=Spree::OptionValue.where(scope).joins(:option_type).where(OptionType.table_name => {:name => "tailleEcran"}).pluck("#{OptionValue.table_name}.id")
Spree::Product.where("#{Product.table_name}.id in (select product_id from #{Variant.table_name} v left join spree_option_values_variants ov on ov.variant_id = v.id where ov.option_value_id in (?))", option_values)
end
def ProductFilters.screenSize_filter
conds = [ [ "20p ou moins",ov_range_test(0,20)],
[ "20p - 30p",ov_range_test(20,30)],
[ "30p - 40p" ,ov_range_test(30,40)],
[ "40p ou plus",ov_range_test(40,190)]]
{ :name => "taille",
:scope => :screenSize_range_any,
:options => :tailleEcran,
:conds => Hash[*conds.flatten],
:labels => conds.map {|k,v| [k,k]}
}
end
You can see this one too, for discrete specific values:
https://gist.github.com/Ranger-X/2511088

Filtering ActiveRecord queries in rails

I'm used to Django where you can run multiple filter methods on querysets, ie Item.all.filter(foo="bar").filter(something="else").
The however this is not so easy to do in Rails. Item.find(:all, :conditions => ["foo = :foo", { :foo = bar }]) returns an array meaning this will not work:
Item.find(:all, :conditions => ["foo = :foo", { :foo = 'bar' }]).find(:all, :conditions => ["something = :something", { :something = 'else' }])
So I figured the best way to "stack" filters is to modify the conditions array and then run the query.
So I came up with this function:
def combine(array1,array2)
conditions = []
conditions[0] = (array1[0]+" AND "+array2[0]).to_s
conditions[1] = {}
conditions[1].merge!(array1[1])
conditions[1].merge!(array2[1])
return conditions
end
Usage:
array1 = ["foo = :foo", { :foo = 'bar' }]
array2 = ["something = :something", { :something = 'else' }]
conditions = combine(array1,array2)
items = Item.find(:all, :conditions => conditions)
This has worked pretty well. However I want to be able to combine an arbitrary number of arrays, or basically shorthand for writing:
conditions = combine(combine(array1,array2),array3)
Can anyone help with this? Thanks in advance.
What you want are named scopes:
class Item < ActiveRecord::Base
named_scope :by_author, lambda {|author| {:conditions => {:author_id => author.id}}}
named_scope :since, lambda {|timestamp| {:conditions => {:created_at => (timestamp .. Time.now.utc)}}}
named_scope :archived, :conditions => "archived_at IS NOT NULL"
named_scope :active, :conditions => {:archived_at => nil}
end
In your controllers, use like this:
class ItemsController < ApplicationController
def index
#items = Item.by_author(current_user).since(2.weeks.ago)
#items = params[:archived] == "1" ? #items.archived : #items.active
end
end
The returned object is a proxy and the SQL query will not be run until you actually start doing something real with the collection, such as iterating (for display) or when you call Enumerable methods on the proxy.
I wouldn't do it like you proposed.
Since find return an array, you can use array methods to filter it, on example:
Item.find(:all).select {|i| i.foo == bar }.select {|i| i.whatever > 23 }...
You can also achive what you want with named scopes.
You can take a look at Searchlogic. It makes it easier to use conditions on
ActiveRecord sets, and even on Arrays.
Hope it helps.
You can (or at least used to be able to) filter like so in Rails:
find(:all, :conditions => { :foo => 'foo', :bar => 'bar' })
where :foo and :bar are field names in the active record. Seems like all you need to do is pass in a hash of :field_name => value pairs.

Resources