Frage

Lassen Sie uns sagen, dass ich ein Formular, in dem Benutzer für Menschen, deren Namen suchen beginnt mit einer bestimmten Zeichenfolge name, zum Beispiel „Mi“ finden würde „Mike“ und „Miguel“. Ich würde wahrscheinlich eine Such Aussage erstellen wie folgt:

find(:all, :conditions => ['name LIKE ?', "#{name}%"])

Lassen Sie uns sagen, dass die Form auch zwei optionale Felder hat, hair_color und eye_color, die verwendet werden können, um die Ergebnisse weiter zu filtern. Das Ignorieren des Namensteils der Abfrage, ein Fund Erklärung für Menschen, die in einer beliebigen Anzahl von optionalen Parametern nehmen könnte wie folgt aussehen:

find(:all, :conditions => { params[:person] })

Was für meine zwei optionale Parameter als Äquivalent dieses verhalten würde:

find(:all, :conditions => { :hair_color => hair_color, :eye_color => eye_color })

Was kann ich nicht herausfinden, wie diese beiden Arten von Abfragen zu verschmelzen, wo das erforderliche Feld „name“ angewandt wird die „wie“ Zustand über, und die optionalen hair_color und eye_color Parameter (und vielleicht auch andere) hinzugefügt werden, um die Ergebnisse weiter zu filtern.

Ich kann auf jeden Fall eine Abfrage-String, dies zu tun aufbauen, aber ich fühle es muss ein „Schienen Weg“ sein, die mehr elegant. Wie kann ich fusionieren zwingend binden Parameter mit optionalen Parametern?

War es hilfreich?

Lösung

Dies ist die perfekte Verwendung eines benannten Umfangs.

Erstellen Sie eine benannte Umfang im Modell:

named_scope :with_name_like, lambda {|name|
  {:conditions => ['name LIKE ?', "#{name}%"]}
}

An dieser Stelle können Sie anrufen

Model.with_name_like("Mi").find(:all, :conditions => params[:person])

Und Rails werden die Abfragen für Sie zusammenführen.

Edit: Code für Waseem:

Wenn der Name ist optional Sie könnten entweder den benannten Umfang von Ihrer Methode Kette mit einer, wenn der Bedingung weglassen:

unless name.blank?
   Model.with_name_like("Mi").find(:all, :conditions => params[:person])
else
   Model.find(:all, :conditions => params[:person])
end

Oder Sie könnten den benannten Rahmen neu zu definieren, das Gleiche zu tun.

named_scope :with_name_like, lambda {|name|
  if name.blank?
    {}
  else
    {:conditions => ['name LIKE ?', "#{name}%"]}
  end
}

Aktualisieren

Hier ist der Rails 3-Version des letzten Code-Snippet:

scope :with_name_like, lambda {|name|
  if not name.blank?
    where('name LIKE ?', "#{name}%")
  end
}

Andere Tipps

Zur Einhaltung auch mit Waseem Anfrage, aber erlaubt nil stattdessen leer? (Was im Falle udeful ist wollen Sie "@things = Thing.named_like (params [: Name])" verwenden, direkt)

named_scope :named_like, lambda do |*args| 
  if (name=args.first)
    {:conditions => ["name like ?",name]}
  else
    {}
  end
end

# or oneliner version:

named_scope :named_like, lambda{|*args| (name=args.first ? {:conditions => ["name like ?",name]} : {}) } }

Ich hoffe, es hilft

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top