Можете да създадете SQL заявка въз основа на вашия хеш. Най-общият подход е необработен SQL, който може да се изпълни от ActiveRecord .
Ето някои концептуален код, който трябва да ви даде правилната идея:
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
Какво прави това:
query_selectуказва каква информация искате в резултатаquery_whereизгражда всички условия за търсене и избягва въвеждането, за да предотврати SQL инжекцииquery_tablesе списък с всички таблици, които трябва да търситеtable_name = table.constantize.table_nameще ви даде SQL table_name, както се използва от моделаraw_queryе действителната комбинирана sql заявка от частите по-гореActiveRecord::Base.connection.execute(raw_query)изпълнява sql в базата данни
Уверете се, че сте поставили всички въведени от потребителя данни в кавички и ги екранирайте правилно, за да предотвратите SQL инжекции.
За вашия пример създадената заявка ще изглежда така:
select * from companies, categories where 'companies'.'name' LIKE 'a%' AND 'companies'.'hq_city' = 'karachi' AND 'categories'.'name' NOT LIKE '%ECommerce%'
Този подход може да се нуждае от допълнителна логика за свързване на свързани таблици. Във вашия случай, ако company и category ако имате асоциация, трябва да добавите нещо подобно към query_where
"AND 'company'.'category_id' = 'categories'.'id'"
Лесен подход: Можете да създадете хеш за всички двойки модели/таблици, които могат да бъдат запитани и да съхранявате подходящото условие за присъединяване там. Този хеш не трябва да е твърде сложен дори за среден проект.
Труден подход: Това може да стане автоматично, ако имате has_many , has_one и belongs_to правилно дефинирани във вашите модели. Можете да получите асоциациите на модел, като използвате reflect_on_all_associations /a> . Реализирайте Breath-First-Search или Depth-First Search алгоритъм и започнете с всеки модел и потърсете съвпадащи асоциации с други модели от вашия json вход. Стартирайте нови работи на BFS/DFS, докато не останат непосетени модели от json входа. От намерената информация можете да извлечете всички условия за присъединяване и след това да ги добавите като изрази в where клауза на необработения sql подход, както е обяснено по-горе. Още по-сложно, но и изпълнимо би било четенето на schema на базата данни и използвайки подобен подход, както е дефиниран тук, като търсите foreign keys .
Използване на асоциации: Ако всички те са свързани с has_many / has_one , можете да обработвате обединяванията с ActiveRecord с помощта на joins метод с inject на "най-значимия" модел като този:
base_model = "Company".constantize
assocations = [:categories] # and so on
result = assocations.inject(base_model) { |model, assoc| model.joins(assoc) }.where(query_where)
Какво прави това:
- той предава base_model като начален вход към Enumerable.inject
, което многократно ще извиква input.send(:joins, :assoc) (за моя пример това ще направи
Company.send(:joins, :categories)което е еквивалентно на `Company.categories - при комбинираното съединение той изпълнява условията where (конструирани, както е описано по-горе)
Отказ от отговорност Точният синтаксис, от който се нуждаете, може да варира в зависимост от SQL реализацията, която използвате.