Das grundlegende Problem mit Ihrer Lösung ist, dass sie jede Ausführung nacheinander erzwingt. Das heißt, wenn der Firmenparameter nil
ist, erhalten Sie eine leere Relation und alle where
-Anweisungen danach werden eine leere Relation zurückgeben. Sie müssen nur bedingt filtern, wenn die Parameter bereitgestellt werden.
Was Sie zu tun versuchen, ist am besten innerhalb eines Abfrage-/Such- oder Filterobjekts erledigt (Abfrage übernimmt Parameter und gibt eine Ergebnismenge zurück, Filter nimmt ein bereits erzeugtes Set und filtert es herunter). Ich mag es, diese in app/services/
zu definieren, obwohl einige Leute sie in app/queries
setzen.
In Ihrer Methode gibt es einige Inkonsistenzen. Ein Indexendpunkt sollte jedoch eine Liste von Objekten zurückgeben. Selbst wenn Sie hoffen, eine einzige Option zu bekommen, sollten Sie erwarten, dass es mehrere geben könnte. Nehmen wir an, wir reparieren Ihren Indexendpunkt und verwenden ein Filterobjekt.
# app/controllers/users_controller.rb
def index
users = User.where(1=1)
users = Users::Filter.call(users, params)
render json: users
end
Sie werde ich User.where(1=1)
verwenden bemerken, ist dies, weil ich den Einsatz für den Umgang mit Schienen 3, die anstelle einer Beziehung ein Array zurückgibt bin, wenn Sie User.all
verwenden.
# /app/services/users/filter.rb
class Users::Filter
def self.call(resources, options)
new(users, options).filter
end
private
attr_reader :resources, :options
def initialize(resources, options)
@resources = resources
@options = options
end
def filter
if options[:company]
@resources = resources.where(company: options[:company])
end
if options[:position]
@resources = resources.where(position: options[:position])
end
resources
end
end
Der Grund, warum ich call
verwenden, die dann die private Methode initialize
und filter
ruft ist so, dass diese Klasse nicht falsch verwendet wird. Es hat einen einzigen Eintrittspunkt und gibt die Ergebnismenge zurück. Dies ermöglicht mir auch, meine Filterfunktionen in kleine, leicht zu wechselnde Stücke zu verwandeln.
Für dieses Beispiel habe ich die Filterung in filter
durchgeführt, aber Sie könnten diese in Methoden ausbrechen und sogar eine clevere Meta-Programmierung verwenden, um den Filternamen aufzurufen, wenn das Objekt darauf reagiert.
EDIT:
Sie auch ein Juwel Lösung zu finden, wie ransack betrachten kann [1], die Sie Parameter direkt auf das Objekt passieren lässt und suchen sie. Es gibt viele verschiedene Arten von Such-/Filter-Edelsteinen, um Ihre Bedürfnisse zu erfüllen.
[1] https://github.com/activerecord-hackery/ransack