Zmienny warunek w zapytaniu

Witam,

mam formularz gdzie wybiera sie wiek od i wiek do. Po zatwierdzeniu formularza, w kontrolerze sprawdzane jest czy pola nie są puste.

[code=“Ruby”]if !params[:min_age].nil?

dołóż warunek age > params[:min_age]

end

if !params[:max_age].nil?

dołóż warunek age < params[:max_age]

end

@users = User.find(:all, WARUNKI)[/code]
Teraz jak to ładnie zapisać, jeżeli któreś pole nie jest puste do należy dołożyć odpowiedni warunek. Podobnych pól może być więcej chodzi schemat zapisu.

Pozdrawiam

:conditions w findzie może być podany jako hash, z nazwą pola jako kluczem - a ActiveRecord już to sobie odpowiednio poskleja

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? :slight_smile:

PaK, rewelacja! Na jakiej licencji jest podany przez Cię kod? :slight_smile:

Piwnej ;] Gdy spotkasz autora, postaw mu piwo :slight_smile:

No to jesteśmy umówieni na WRUGu grudniowym jak rozumiem :smiley:

Baa :slight_smile: mam nadzieje ze tym razem znajde czas :wink: