Отвечая на мой собственный вопрос здесь. Самый элегантный и лаконичный способ, который я нашел для этой работы, заключался в том, чтобы перейти прямо в Арель. Кроме того, были некоторые проблемы с отправленным исходным кодом, но даже все же мне нужно было использовать arel, чтобы получить правильно сгруппированные условия. Для контекста у меня есть объект, который, основываясь на связанных данных, должен динамически создавать полусложный запрос, поэтому я хотел сделать такие вещи, как проверка на наличие определенных связанных данных, и, если он присутствует, затем добавить дополнительные соединения и роды. Вот окончательные версии соответствующих методов:
def find_observations
observations = Observation.select('distinct observations.*').includes(:obs_session).includes(:judgements).includes(:concepts).includes(:obs_descriptors)
observations = observations.joins(:obs_session => :project).where(:obs_sessions=>{:project_id=>self.project.id})
if tag_descriptors && tag_descriptors.size > 0
observations = observations.where(descriptor_predicate)
end
if session_descriptors && session_descriptors.size > 0
observations = observations.where(session_predicate)
end
if user_descriptors && user_descriptors.size > 0
observations = observations.where(user_predicate)
end
#puts "observations sql is: #{observations.to_sql}"
observations.all
end
Приведенный выше метод необязательно вызывает остальные методы, которые возвращают арель, используемый в вызовах where при сцеплении объекта AR при построении возможного запроса. Обратите внимание на различие; У меня была версия этого, полностью использующая arel, которая, казалось, работала, но фактически возвращала дубликаты. Я нашел ссылки на использование group (some_attribute) для фальсификации вещей, но это, так сказать, привело к проблемам в цепочке. Поэтому я вернулся к использованию ActiveRelation, чтобы указать отличительные элементы, объединения и включения, а также остальное.
Следующей была часть, которая изначально доставляла мне много хлопот; существует переменное число возможностей, и каждая из них может быть условием AND или OR, и их необходимо сгруппировать отдельно, чтобы не испортить остальную часть сгенерированного предложения where.
def descriptor_predicate
od = Arel::Table.new :obs_descriptors
predicate = nil
self.tag_descriptors.each_index do |index|
descriptor = self.tag_descriptors.fetch(index)
qual_key = descriptor.qualifier_key
tag_name = descriptor.tag_name
if index == 0
predicate = od[:descriptor].eq(tag_name)
else
if qual_key == "OR"
predicate = predicate.or(od[:descriptor].eq(tag_name))
else
predicate = predicate.and(od[:descriptor].eq(tag_name))
end
end
end
predicate
end
И, наконец, другие методы предикатов для значений потенциальных объединенных сущностей:
def session_predicate
o = Arel::Table.new :observations
predicate = nil
self.session_descriptors.each_index do |index|
obs = self.session_descriptors.fetch(index)
if index == 0
predicate = o[:obs_session_id].eq(obs.entity_id)
else
predicate = predicate.or(o[:obs_session_id].eq(obs.entity_id))
end
end
predicate
end
def user_predicate
o = Arel::Table.new :observations
predicate = nil
self.user_descriptors.each_index do |index|
obs = self.user_descriptors.fetch(index)
if index == 0
predicate = o[:contributor_id].eq(obs.entity_id)
else
predicate = predicate.or(o[:contributor_id].eq(obs.entity_id))
end
end
predicate
end
def descriptor_where_string(included_where_statements)
tag_descriptors.each_index do |index|
qual_key = tag_descriptors.fetch(index).qualifier_key
tag_name = tag_descriptors.fetch(index).tag_name
if index == 0
query_string = "obs_descriptors.descriptor = #{tag_name}"
else
if qual_key == "OR"
query_string = query_string + " #{qual_key} obs_descriptors.descriptor = #{tag_name} AND #{included_where_statements} "
else
query_string = query_string + " #{qual_key} obs_descriptors.descriptor = ?"
end
end
end
query_string
end
В конечном счете, я нашел лучшее решение, включающее использование цепочек ActiveRelation для предоставления отличительных и включаемых элементов и непосредственное использование arel для условий связанных значений. Надеюсь, что в какой-то момент это кому-нибудь поможет.