Oczywiscie jesli zalezy ci tylko na warunku ‘equal’ LIKE albo BETWEEN juz nie wchodzi w gre.
Ja stworzylem sobie klase BaseFilter
[code]class BaseFilter
attr_reader :filter_hash
@@allowed_keys = [
]
def blank?
@filter_hash.blank?
end
def initialize(hash = {})
if hash.is_a?(Hash)
hash.each_key { |key| hash.delete(key) unless @@allowed_keys.include?(key) }
@filter_hash = hash
else
@filter_hash = {}
end
end
def method_missing(method_name)
if @filter_hash[method_name]
@filter_hash[method_name]
end
end
def to_sql
“”
end
def dump
Base64::encode64(@filter_hash.to_yaml)
end
if filter_dump is empty or invalid will return nil
def self.load_dump(filter_dump)
hash = (YAML::load(Base64::decode64(filter_dump)) rescue ‘’)
unless hash.blank?
new(hash)
else
nil
end
end
end[/code]
Ktora tworzona jest na podstawie params[:filter] np.
@filter = Filter.new(params[:filter])
Dzieki czemu helpery w formularzac moga bez problemu korzysta z tego obiektu.
text_field('filter','name') # odwola sie do @filter.name
Oprocz tego pozwala na latwe tworzenie dumpa takiego filtra (przekazywanego jako parametr przy paginacji) lub zapisywanego w tabeli bazy danych (np dump filtra zapisany jako Folder)
Dump:
>> UserFilter.new('search' => 'test').dump
=> "LS0tIApzZWFyY2g6IHRlc3QK\n"
Dump Load:
>> UserFilter.load_dump("LS0tIApzZWFyY2g6IHRlc3QK\n")
=> #<UserFilter:0xb72b629c @filter_hash={"search"=>"test"}
Przykladowy filtr:
>> UserFilter.new('search' => 'test').to_sql
=> ["(users.name LIKE ? OR users.last_name LIKE ? OR users.first_name LIKE ? OR users.email LIKE ? OR phones.phone_number LIKE ?)", "%test%", "%test%", "%test%", "%test%", "%test%"]
Tworzac nowy filtr, nalezy overloadnac tylko nowa metode to_sql i dodac tablice mozliwych klucz
[code]class UserFilter < BaseFilter
@@allowed_keys = [
“search”,
“active”,
“type”,
“vip”,
“role_id”,
“client_id”,
“client_name”
]
def to_sql
Condition.block do |c|
@filter_hash.each do |key, value|
unless value.blank?
case key
when /search/
c.and do |ca|
search = value.downcase.gsub(/ /, ‘%’)
ca.or(“users.name”, “LIKE”, “%#{search}%”)
ca.or(“users.last_name”, “LIKE”, “%#{search}%”)
ca.or(“users.first_name”, “LIKE”, “%#{search}%”)
ca.or(“users.email”, “LIKE”, “%#{search}%”)
ca.or(“phones.phone_number”, “LIKE”, “%#{search}%”)
end
when /client_id/
c.and(“users.client_id”, value)
when /active|vip/
c.and(“users.#{key}”, “IN”, value)
when /type/
c.and(“users.type”, “IN”, value)
when /role_id/
c.and(“roles_users.role_id”, value)
end
end
end
end
end
end[/code]
to_sql budowane jest na podstawie przerobionego http://agilewebdevelopment.com/plugins/condition_builder (po migracji do rails 2.2 mam zamiar przejsc na http://github.com/thoughtbot/squirrel/tree/master)
Przykladowy finder wygladal by tak:
User.find(:all, :conditions => UserFilter.new({'search' => 'test'}).to_sql, :include => [:phones, :roles])
Niestety obecnie implementacja nie tworzy tablicy joinow, squirrel w zasadzie wyeliminuje ten problem.
A tak by wygladal twoj filtr
[code]class UserFilter2 < BaseFilter
@@allowed_keys = [
“min_age”,
“max_age”,
]
def to_sql
Condition.block do |c|
@filter_hash.each do |key, value|
unless value.blank?
case key
when /min_age/
c.and(“users.min_age”, “>=”, value)
when /max_age/
c.and(“users.max_age”, “<=”, value)
end
end
end
end
end
end[/code]
A tak by dzialal
>> UserFilter2.new('min_age' => '10', 'max_age' => '20').to_sql
=> ["users.min_age >= ? AND users.max_age <= ?", "10", "20"]
Nie stosuje symboli w nazwach, poniwaz params[] zawiera i tak tylko i wylacznie string jako klucz.Prawda? 