Можете да създадете 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 реализацията, която използвате.