У меня есть то, что на самом деле является обычной ситуацией в Rails, где у меня есть модель, которая имеет две ассоциации. Я хочу иметь возможность поиска определенных записей, определенных моделью, на основе условий одной или обеих этих ассоциаций.
Суть в том, что эти две ассоциации используют одну и ту же таблицу.
Вот основная модель:
class Resource < ActiveRecord::Base
belongs_to :primary_item, class_name: 'Item', foreign_key: 'primary_item_Id'
belongs_to :secondary_item, class_name: 'Item', foreign_key: 'secondary_item_Id'
...
И модель Item
:
class Item < ActiveRecord::Base
has_many :res_primary, class_name: 'Resource', foreign_key: 'primary_item_Id'
has_many :res_secondary, class_name: 'Resource', foreign_key: 'secondary_item_Id'
...
Предположим, что Item
имеет строковое поле с именем name
. Это просто название предмета. Я хочу быть в состоянии найти все ресурсы, которые имеют основной и / или дополнительный элемент, который похож на данное имя. Вот как это выглядит (я думаю), если я просто фильтрую основной элемент:
@resources.joins(:primary_item)
.where("#{Item.table_name}.name like #{primary_search_string}")
primary_search_string
- это просто строка, которую я хочу найти в name
. Это отлично работает. Аналогичный поиск работает для вторичных предметов.
Теперь предположим, что я бы хотел, чтобы пользователь мог искать ресурсы, которые имеют либо заданное имя первичного элемента, либо заданный вторичный элемент по имени, либо оба (каждый со своим собственным именем). Я бы имел primary_search_string
и secondary_search_string
с независимыми значениями. Одним из них может быть nil
, что означает, что я не хочу сужать поиск, основанный на этой строке. Я хочу фильтровать ресурсы по одной или обеим строкам в зависимости от того, являются ли они nil
. Вот то, что я закончил с тем, что работает, но кажется неловким:
@resources = <some query that obtains an active record relation of resources>
if primary_search_string then
@resources = @resources.joins(:primary_item)
.where("#{Item.table_name}.name like #{primary_search_string}")
if secondary_search_string then
@resources = @resources.joins(:secondary_item)
.where("secondary_items_#{Item.table_name}.name like #{secondary_search_string}")
end
elsif secondary_search_string then
@resources = @resources.joins(:secondary_item)
.where("#{Item.table_name}.name like #{secondary_search_string}")
end
Обратите внимание, что если я присоединяюсь только к одной таблице, имя таблицы известно как Item.table_name
. Однако, если мне нужно объединить обе таблицы, Rails должен различить второй экземпляр таблицы, указав еще имя с именем ассоциации: secondary_items_#{Item.table_name}
.
Мой вопрос заключается в том, есть ли несколько более простой способ справиться с этим, который не требует ссылки на имена таблиц ассоциаций в предложениях where
? Так как я ссылаюсь на имена таблиц ассоциаций, и имя таблицы может отличаться в зависимости от того, присоединяюсь ли я к одному из них или к обоим, я в итоге проверяю строку поиска на nil
, что является способом определить, присоединяюсь ли я к таблице Item
более одного раза. В этом конкретном примере программы я могу проверить это и жить с этим, будучи неловким. Но что, если я не знаю, был ли ранее @resources
присоединен к основным элементам, и я хотел фильтровать на основе дополнительных элементов? В этом случае я бы не знал, какое имя таблицы ассоциаций будет использоваться в предложении where
, поскольку я не знаю, было ли оно уже join
или нет.
Я подозреваю, что здесь может быть лучший путь, который является сутью моего вопроса.