Suchfunktion mit 2 Kritieren

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Suchfunktion mit 2 Kritieren

    Ich habe in meinem Projekt eine Suchfunktion die nach 2 Kritieren suchen soll und nur jene ergebnisse liefert auf die beide Zutreffen, also nur wenn das Suchwort als Tag gespeichert und die gewählte Programmiersprache übereinstimmt, sodass z.B. wenn man nach "sort" sucht und Java einstellt, Ergebnisse für C kommen.
    Leider ist es mir bislang nicht gelungen das das auch funktioniert. Die Suche nach einem Tag funktioniert ohne Probleme, sowie ich versuche die Programmiersprache miteinzubeziehen, geht gar nichts mehr.

    Konkret sieht das in meinem Programm so aus:


    Model:

    Quellcode

    1. def self.search(search, lang)
    2. if search
    3. find(:all, :conditions => ['tags LIKE ?', "%#{params[:search]}%"])
    4. else
    5. find(:all)
    6. end
    7. end


    View:

    Quellcode

    1. <% form_tag :controller => 'code_snippets', :method => 'get' do %>
    2. <p>
    3. <%= text_field_tag :search, params[:search] %>
    4. <%= select_tag (:lang, options_for_select(["C", "C++", "CSS", "HTML", "Java", "Javascript", "RHTML", "Python", "Ruby", "SQL", "XML"]), {:multiple => false}) %>
    5. <%= submit_tag "Search", :name => nil %>
    6. </p>
    7. <% end %>


    Controller:

    Quellcode

    1. def index
    2. if params[:search]
    3. search_condition = "%#{params[:search]}%"
    4. @code_snippets = CodeSnippet.find(:all, :conditions => ['tags LIKE ?', search_condition])
    5. # @code_snippets = CodeSnippet.find(:all, :conditions => ['tags LIKE ? AND language LIKE ?', search_condition, :lang])
    6. else
    7. @code_snippets = CodeSnippet.find(:all)
    8. end
    9. end


    Im Model hab ich jetzt die Versuche wieder rückgängig gemacht und nur die Suche nach den Tags drinnen, weil eben alles andere dazu geführt hat das gar nichts mehr geht. Im Controller hab ich die Zeile auskommentiert in der beide gesucht werden sollten. Ich hoffe jemand kann mir hier helfen damit das ganze funktioniert.
    Vielen Dank!
  • Benötigst du denn das LIKE? EIgentlich braucht man das doch nur, wenn man nach Mustern sucht, was du anscheinend ja noch nicht tust :huh:

    Es gibt verschiedene Wege:

    1. Nutze die dynamischen Finder-Methoden in Rails. Dann sieht deine Abfrage etwas so aus:

    Quellcode

    1. @code_snippets = CodeSnippet.find_all_by_tags_and_lang(tags, language)


    2. Hol erst alle Snippets für die gesuchte Sprache, dann filtere die Tags

    Quellcode

    1. @code_snippets = CodeSnippet.find_all_by_lang(language)
    2. # je nach Datenstruktur die Snippets untersuchen


    3. Untersuche, warum deine SQL-Anweisung fehl schlägt. Dazu schaust du zuerst im Log, welche SQL-Anweisung wirklich gesendet wird (sind die Variablen richtig übergeben worden oder sind sie evtl. leer?). Falls die SQL-Anweisung an sich richtig ausschaut, führe sie doch mal direkt auf mySQL aus. Dazu kannst du am besten phpmyadmin oder einen mysql-Client nutzen.

    4. Ersetze das LIKE, z.B. mit einem einfachen Vergleich (=)

    EDIT: Ich habe gerade gesehen, dass du doch nach Mustern suchst. Dann fallen einige Lösungsmöglichkeiten weg. (Wobei ich persönlich zuerst eine direkte Suche in Betracht ziehen und später eine unscharfe Suche einbauen würde.) Schau einfach mal, was wirklich als SQL ausgeführt wird und ob die Variablen richtig übergeben werden. Dazu kannst du jederzeit selbst im Controller Daten loggen. Einiges steht auch standardmäßig im Log. Schau einfach mal rein...
  • Das Problem mit dem SQL Log ist, dass meine Index Seite gar nicht mehr geöffnet werden kann weil Rails irgendeine Fehlermeldung ausgibt die sich auf das lang Attribut im View bezieht das unbekannt ist. Da fehlt glaube ich noch was im Controller oder Model, aber alle bisherigen Versuche das einzubauen sind leider gescheitert.
    Daher kann ich keine Suche mehr starten, also werden wahrscheinlich gar keine SQL Befehle abgesetzt.

    Das mit der direkten und unschafen Suche habe ich nicht ganz verstanden, wo liegt da genau der Unterschied?
    Mein Problem ist, dass ich einen Tags String habe in dem mehrere Tags stehen können. Der soll jetzt durchsucht werden und jeder Eintrag wo der gesuchte Tag drinnen vorkommt soll angezeigt werden. Das funktioniert bislang auch gut, wenn auch noch die Programmiersprache berücksichtigt werden würde, wäre es perfekt.
    Ich glaube aber, dass es weniger ein Problem mit der Berücksichtigung ist, sondern mit der Übergabe der Parameter. Leider kann ichs momentan ohne Ruby nicht testen, das müßte ja mit einer einfachen Textausgabe der Parameter funktionieren. Wenn ich die einfüge und dann auf der Seite beide Suchparameter stehen dann funktionert die Übergabe und es liegt an der Suche selbst, sonst wohl eher an der Übergabe.
  • Dann informiere uns doch bitte erstmal, welche Fehlermeldung denn kommt. Meistens kann man da relativ genau ableiten, was zu tun ist.

    Mit der unscharfen/direkten Suche meinte ich das so:
    Eine unscharfe Suche verwendet LIKE. Das ist bei den Tags auch notwendig, da du nur einen String hast. Allerdings könntest du erstmal alle Snippets holen, die einer Sprache zugehören. Das machst du mit einer direkten Suche (WHERE lang = 'Java' o.ä.). Das erfordert natürlich, dass du immer gleiche Sprachbezeichnungen speicherst. Danach könntest du die tags durchsuchen...

    Mal ne andere Frage: Wie hattest du die Sprachen angelegt? Als einzelnes Model? oder als String in dem Snippets-Model? Falls es ein eigenes Model ist, könnte der Fehler auch daher kommen...
  • Die Sprache ist als String gespeichert, wird aber über ein select field eingegeben, d.h. die Schreibweise ist überall gleich.

    Ich hab jetzt doch mal schnell Ruby auf dem Bürorechner installiert um das schnell zu probieren (welch ein Vorteil das unser EDV Verantwortlicher keine Ahnung hat und so jeder User volle Adminrechte geniesst :-D).
    Fehlermeldung bekomme ich hier aber merkwürdigerweise gar keine, allerdings bleibt die Liste leer wenn ich nach beiden Kriterien suche. Das

    Quellcode

    1. Language <% :lang %>
    gibt mir auf der Ausgabeseite dann auch nur "Language" aus, es scheint also wirklich nichts übergeben zu werden und daher wird dann eben kein Snippet gefunden, das keine Sprache hat. Vielleicht vereinfacht das die Suche nach dem Fehler?
  • Lass dir doch mal den Params-Hash im Controller ausgeben, am besten mit

    Quellcode

    1. RAILS_DEFAULT_LOGGER.debug params.inspect


    Da siehst du dann (im Log der jeweiligen Environment), welche Daten überhaupt ankommen und wie du darauf zugreifen kannst. Im Controller gehst du ja bis jetzt davon aus, dass die Sprache in :lang drinsteht. Das dürfte aber nicht der Fall sein. eher in params[:lang]. Schau aber am besten in den params-Hash, da sieht man es genau...
  • So wie ich das Log verstehe, scheint es tatsächlich so, als ob die Sprache zwar erfasst wird, dann aber nicht übergeben wird bzw. nicht für die Suche verwendet wird.
    Wenn ich aber

    Quellcode

    1. if params[:search]
    auf

    Quellcode

    1. if params[:search, :lang]
    ändere um beide Parameter zu berücksichtigen bekomme ich sofort die Fehlermeldung, dass ich hier eine falsche Anzahl an Argumenten habe (2 statt 1)
    Wenn ich es so mache, dass ich erst nach der Sprache filtere und dann nach den Tags wird die Sprache ignoriert, da stimmt bei mir wohl auch was nicht.

    Quellcode

    1. if params[:search]
    2. search_condition = "%#{params[:lang]}%"
    3. @code_snippets = CodeSnippet.find(:all, :conditions => ['language LIKE ?', search_condition])
    4. search_condition = "%#{params[:search]}%"
    5. @code_snippets = CodeSnippet.find(:all, :conditions => ['tags LIKE ?', search_condition])
    6. else
    7. @code_snippets = CodeSnippet.find(:all)
    8. end
    9. end


    Irgendwas mache ich also offensichtlich falsch

    Anbei noch das Log für den Fall das es hilft:
    Processing CodeSnippetsController#index (for 127.0.0.1 at 2010-06-10 22:42:00) [POST]
    Parameters: {"search"=>"hello", "authenticity_token"=>"FNi7IDaXYSz2B8OiyGmHXwuITs2NphkU3TvBl9emMqA=", "method"=>"get", "lang"=>"Python"}
    {"search"=>"hello", "authenticity_token"=>"FNi7IDaXYSz2B8OiyGmHXwuITs2NphkU3TvBl9emMqA=", "action"=>"index", "method"=>"get", "controller"=>"code_snippets", "lang"=>"Python"}
    [4;36;1mCodeSnippet Load (1.0ms)[0m [0;1mSELECT * FROM "code_snippets" WHERE (tags LIKE '%hello%' AND language LIKE '--- :lang
    ') [0m
    Rendering template within layouts/application
    Rendering code_snippets/index
    Rendered code_snippets/_search (2.0ms)
    Completed in 15ms (View: 6, DB: 1) | 200 OK [127.0.0.1/?method=get]
  • Also deine If-Abfrage schlägt natürlich fehl, weil Ruby zwar weiß, wie man einen Ausdruck auswertet, aber sicher nicht weiß, was du da machen willst.

    Du willst ja eigentlich folgendes: Wenn deine Parameter gefüllt sind, soll die Suche starten, da würde eher sowas in Frage kommen:

    Quellcode

    1. unless params[:search].nil? && params[:lang].nil?
    2. search_condition = "%#{params[:search]}%"
    3. @code_snippets = CodeSnippet.find(:all, :conditions => ['tags LIKE ? AND language = ?', search_condition, params[:lang]])
    4. else
    5. @code_snippets = CodeSnippet.find(:all)
    6. end


    "unless" ist gleichzusetzen mit "not if", es prüft also, ob deine Ausdrücke nicht nil sind und macht dann weiter... Danach fragst du mit Hilfe der Parameter ab...
  • Hallo!

    Vielen Dank für deinen Tipp, ich werde das gleich heute ausprobieren und hoffe es klappt.
    Den unless Befehl kannte ich bislang nicht, macht aber Sinn. Hier zeigt sich wohl einmal mehr meine fehlende Programmiererfahrung, ganz zu schweigen davon, dass man sich mit RoR wirklich gut auskennen muss um damit zurecht zu kommen. Dann geht zwar alles schnell und einfach, aber wenn man die Konventionen nicht kennt und verstanden hat, ist man sehr schnell aufgeschmissen.

    Ich habe heute Nachmittag einen Termin mit dem Prof und werde ihm dann die hoffentlich funktionierende Variante sowie meine überarbeitete und ergänzte Arbeit vorlegen und mit etwas Glück passt es dann schon.
    Nochmals Tausend Dank für deine Hilfe, ohne die wäre ich wohl schon lange durchgefallen!!!
  • "Unless" kenne ich auch nur in Ruby. Andere Sprachen bieten maximal "not if" oder "!if" oder ähnlich...

    Falls du mit unless nicht klar kommst:

    Quellcode

    1. # || steht für ODER (&& steht übrigens für UND)
    2. if params[:search].nil? || params[:lang].nil?
    3. # Fehlerfall: Alle Snippets holen
    4. else
    5. # kein Fehler: entsprechende Snippets holen
    6. end


    Alternativ kannst du auch prüfen, ob die Variablen leer sind:

    Quellcode

    1. if params[:search].blank? || params[:lang].blank?
    2. # Fehlerfall: Alle Snippets holen
    3. else
    4. # kein Fehler: entsprechende Snippets holen
    5. end