Sie können eine SQL-Abfrage basierend auf Ihrem Hash erstellen. Der allgemeinste Ansatz ist rohes SQL, das von ActiveRecord
ausgeführt werden kann .
Hier ist ein Konzeptcode, der Ihnen die richtige Vorstellung vermitteln sollte:
query_select = "select * from "
query_where = ""
tables = [] # for selecting from all tables
hash.each do |table, values|
table_name = table.constantize.table_name
tables << table_name
values.each do |q|
query_where += " AND " unless query_string.empty?
query_where += "'#{ActiveRecord::Base.connection.quote(table_name)}'."
query_where += "'#{ActiveRecord::Base.connection.quote(q[fieldName)}'"
if q[:operator] == "starts with" # this should be done with an appropriate method
query_where += " LIKE '#{ActiveRecord::Base.connection.quote(q[val)}%'"
end
end
end
query_tables = tables.join(", ")
raw_query = query_select + query_tables + " where " + query_where
result = ActiveRecord::Base.connection.execute(raw_query)
result.to_h # not required, but raw results are probably easier to handle as a hash
Was das bewirkt:
query_select
gibt an, welche Informationen Sie im Ergebnis haben möchtenquery_where
erstellt alle Suchbedingungen und maskiert die Eingabe, um SQL-Injektionen zu verhindernquery_tables
ist eine Liste aller Tabellen, die Sie durchsuchen müssentable_name = table.constantize.table_name
gibt Ihnen den SQL-Tabellennamen, wie er vom Modell verwendet wirdraw_query
ist die eigentliche kombinierte SQL-Abfrage aus den obigen TeilenActiveRecord::Base.connection.execute(raw_query)
führt das SQL auf der Datenbank aus
Stellen Sie sicher, dass alle Benutzereingaben in Anführungszeichen gesetzt und korrekt maskiert werden, um SQL-Einschleusungen zu verhindern.
Für Ihr Beispiel sieht die erstellte Abfrage folgendermaßen aus:
select * from companies, categories where 'companies'.'name' LIKE 'a%' AND 'companies'.'hq_city' = 'karachi' AND 'categories'.'name' NOT LIKE '%ECommerce%'
Dieser Ansatz erfordert möglicherweise zusätzliche Logik zum Zusammenführen verwandter Tabellen. In Ihrem Fall, wenn company
und category
eine Assoziation haben, müssen Sie so etwas zu query_where
hinzufügen
"AND 'company'.'category_id' = 'categories'.'id'"
Einfacher Ansatz: Sie können für alle abfragbaren Paare von Modellen/Tabellen einen Hash erstellen und dort die entsprechende Join-Bedingung hinterlegen. Dieser Hash sollte selbst für ein mittelgroßes Projekt nicht zu komplex sein.
Harter Ansatz: Dies kann automatisch erfolgen, wenn Sie has_many
haben , has_one
und belongs_to
richtig in Ihren Modellen definiert. Sie können die Zuordnungen eines Modells mit reflect_on_all_associationsBreath-First-Search
oder Depth-First Search
Algorithmus und beginnen Sie mit einem beliebigen Modell und suchen Sie nach passenden Assoziationen zu anderen Modellen aus Ihrer json-Eingabe. Starten Sie neue BFS/DFS-Läufe, bis keine nicht besuchten Modelle aus der json-Eingabe übrig sind. Aus den gefundenen Informationen können Sie alle Join-Bedingungen ableiten und diese dann als Ausdrücke im where
einfügen -Klausel des Raw-SQL-Ansatzes, wie oben erläutert. Noch aufwendiger, aber auch machbar wäre das Auslesen des schema
der Datenbank und verwenden Sie einen ähnlichen Ansatz wie hier definiert, indem Sie nach foreign keys
suchen .
Assoziationen verwenden: Wenn alle mit has_many
verknüpft sind / has_one
, können Sie die Joins mit ActiveRecord
handhaben durch Verwendung der joins
Methode mit inject
auf dem "bedeutendsten" Modell so:
base_model = "Company".constantize
assocations = [:categories] # and so on
result = assocations.inject(base_model) { |model, assoc| model.joins(assoc) }.where(query_where)
Was das bewirkt:
- es übergibt das base_model als Starteingabe an Enumerable.inject
, die wiederholt input.send(:joins, :assoc) aufruft (in meinem Beispiel würde dies
Company.send(:joins, :categories)
tun was äquivalent zu `Company.categories
ist - beim kombinierten Join führt es die where-Bedingungen aus (wie oben beschrieben aufgebaut)
Haftungsausschluss Die genaue Syntax, die Sie benötigen, kann je nach verwendeter SQL-Implementierung variieren.