[RoR] Hash zu Conditions-Array für Model.find() konvertieren

Vielleicht kann ja jemand diese Funktion gebrauchen, mir hat sie bei mehreren Filtermethoden sehr geholfen, da ich nur noch neue Formularfelder einfügen musste, um die Suche zu erweitern, den Rest hat die Funktion übernommen.
Ich bin mir sicher, es gibt einfachere Wege, um das zu erreichen, aber so hat es jedenfalls funktioniert.

Nutzungsbeispiel:

1
2
3
4
5
#params[:search_details] muss ein hash sein, dessen key jeweils dem tabellen-feldnamen entspricht (also z.B.
<input name="search_details[table.fieldname]" type="text" />
conditions = hash2conditions params[:search_details], { :additional =&gt; "table.canceled &lt;&gt; 1", :compare =&gt; "LIKE"}
...
@list = Model.find(:all, :conditions =&gt; conditions)

Sonderfall: Concat
In manchen Fällen kann es sinnvoll sein, nach einem Zusammengesetzen Datenbankfeld zu fahnden, beispielsweise, wenn Vor- und Zuname einer Person in unterschiedlichen Feldern gespeichert werden. In diesem Fall muss der key des hashs (= der Name des Textfeldes) folgendermaßen aufgebaut sein:

1
2
hash = { "vorname| |zuname" =&gt; "max mustermann"}
# =&gt; ["LOWER(CONCAT(vorname, ' ', zuname)) LIKE ?", "max mustermann"]

Hilfs- und Hauptfunktion:

1
2
3
4
#Benötigte Funktion zum escapen des SQL-Statements
def mysql_escape_string string
	string.gsub(/["';]/, "")
end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#konvertiert einen hash in ein conditions-array für Model.find()
def hash2conditions _hash, options = { :compare => "LIKE", :additional => ""}
	conditions = {}
	conditions[:fields] = []
	conditions[:values] = []			
	if _hash
		_hash.each do |key, value|
			#sql-injections verhindern
			key = mysql_escape_string key
			_hash[key] = mysql_escape_string _hash[key]
			unless _hash[key].blank?
				#Wenn compare-methode "like" und der wert kein Integer ist
				if options[:compare].downcase == "like" and _hash[key].to_i.to_s != _hash[key]
					#Concat, zusammengesetzte Werte, wie z.B. contacts.first_name + " " + "contacts.last_name"
					if key.split("|").size > 1
						field = "LOWER(CONCAT(" + key.split("|").join(",").gsub(" ", "' '") + ")) " + options[:compare] + " ?"
					else
						field = "LOWER(" + key + ") " + options[:compare] + " ?"
					end
					value = "%" + _hash[key].downcase + "%"
				else
					#Integer-Wert, = wird in jedem fall genommen
					if _hash[key].to_i.to_s == _hash[key]
						field = key + " = ?"
					else
						field =  key + " " + options[:compare] + " ?"
					end
					value =  _hash[key]
				end
				if _hash[key] == "NULL"
					field = key + " IS NULL"
					value = ""
				end
				conditions[:fields] < < field
				conditions[:values] << value unless value.blank?
			end
		end
	end
	#addional-wert an conditions anfügen
	conditions[:fields] << options[:additional] unless options[:additional].blank?
	conditions[:fields] = conditions[:fields].join(" AND ")
	array = []
	#conditions-array bilden
	array << conditions[:fields]
	conditions[:values].each do |value|
		array << value
	end
	return array
end

Tags: , , ,

Dienstag, Februar 17th, 2009 Programmierung

Kommentar verfassen

Back to Top ↑