Du kan oprette en SQL-forespørgsel baseret på din hash. Den mest generiske tilgang er rå SQL, som kan udføres af ActiveRecord
.
Her er noget konceptkode, der burde give dig den rigtige idé:
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
Hvad dette gør:
query_select
angiver, hvilke oplysninger du ønsker i resultatetquery_where
bygger alle søgebetingelser og undslipper input for at forhindre SQL-injektionerquery_tables
er en liste over alle de tabeller, du skal søge itable_name = table.constantize.table_name
vil give dig SQL-tabelnavnet som brugt af modellenraw_query
er den faktiske kombinerede sql-forespørgsel fra delene ovenforActiveRecord::Base.connection.execute(raw_query)
udfører sql på databasen
Sørg for at sætte ethvert brugerindsendt input i anførselstegn og undgå det korrekt for at forhindre SQL-injektioner.
For dit eksempel vil den oprettede forespørgsel se sådan ud:
select * from companies, categories where 'companies'.'name' LIKE 'a%' AND 'companies'.'hq_city' = 'karachi' AND 'categories'.'name' NOT LIKE '%ECommerce%'
Denne tilgang kræver muligvis yderligere logik for at forbinde tabeller, der er relaterede. I dit tilfælde, hvis company
og category
har en tilknytning, skal du tilføje noget som dette til query_where
"AND 'company'.'category_id' = 'categories'.'id'"
Nem tilgang: Du kan oprette en Hash for alle par af modeller/tabeller, der kan forespørges på, og gemme den passende forbindelsestilstand der. Denne Hash bør ikke være for kompleks, selv for et mellemstort projekt.
Hård tilgang: Dette kan gøres automatisk, hvis du har has_many
, has_one
og belongs_to
korrekt defineret i dine modeller. Du kan få tilknytningerne til en model ved at bruge reflect_on_all_associations . Implementer en Breath-First-Search
eller Depth-First Search
algoritme og start med en hvilken som helst model og søg efter matchende associationer til andre modeller fra din json-input. Start nye BFS/DFS-kørsler, indtil der ikke er nogen ubesøgte modeller tilbage fra json-inputtet. Ud fra de fundne oplysninger kan du udlede alle joinbetingelser og derefter tilføje dem som udtryk i where
klausul af raw sql-tilgangen som forklaret ovenfor. Endnu mere komplekst, men også muligt, ville være at læse databasens schema
og bruge en lignende tilgang som defineret her ved at lede efter foreign keys
.
Brug af tilknytninger: Hvis alle er forbundet med has_many
/ has_one
, kan du håndtere joins med ActiveRecord
ved at bruge joins
metode med inject
på den "mest betydningsfulde" model som denne:
base_model = "Company".constantize
assocations = [:categories] # and so on
result = assocations.inject(base_model) { |model, assoc| model.joins(assoc) }.where(query_where)
Hvad dette gør:
- den sender base_modellen som startinput til Enumerable.inject
, som gentagne gange kalder input.send(:joins, :assoc) (for mit eksempel ville dette gøre
Company.send(:joins, :categories)
hvilket svarer til `Company.categories - på den kombinerede join udfører den where-betingelserne (konstrueret som beskrevet ovenfor)
Ansvarsfraskrivelse Den nøjagtige syntaks, du har brug for, kan variere baseret på den SQL-implementering, du bruger.