Как использовать Arel:: Nodes:: TableAlias ​​в начале, где оператор

Я застрял на этом и, конечно же, легко, но я просто не могу найти решение в документах.

У меня есть некоторая древовидная структура и предложение child where, которое я должен фильтровать с помощью суб-запроса "exist":

current_node.children.as("children_nodes").where(Node.where(...).exists)

Node.where.clause уже присоединяется к children_nodes и работает, если я использую две разные модели. Но как я могу использовать псевдоним? Вышеуказанный код приведет к:

NoMethodError (undefined method `where' for #<Arel::Nodes::TableAlias

Это так просто, но что-то мне не хватает (я слишком новичок в isl).

Ответ 1

как метод генерирует объект isl, который не имеет метода, такого как объект Relation объект Arel генерирует sql для выполнения в основном своего диспетчера select вы можете использовать union и дать ему другое условие, а затем использовать to_sql например:

arel_obj = current_node.children.as( "children_nodes" ). Союз (Node.where(....)

sql_string = arel_obj.to_sql

Node.find_by_sql (SQL_string)

вот некоторые ссылки, которые могут помочь http://www.rubydoc.info/github/rails/arel/Arel/SelectManager

Ответ 2

В Arel, as будет выполняться все до этой точки и использовать его для создания именованного подзапроса, который можно поместить в предложение FROM. Например, current_node.children.as("children_nodes").to_sql напечатает что-то вроде этого:

(SELECT nodes.* FROM nodes WHERE nodes.parent_id = 5) AS children_nodes

Но похоже, что вы действительно хотите дать псевдоним SQL в таблице nodes. Технически вы можете сделать это с помощью FROM:

current_node.children.from("nodes AS children_nodes").to_sql

Но если вы это сделаете, многие другие вещи сломаются, потому что остальная часть запроса все еще пытается SELECT nodes.* и фильтровать WHERE nodes.parent_id = 5.

Итак, я думаю, что лучший вариант - не использовать псевдоним или написать свой запрос с помощью find_by_sql:

Node.find_by_sql <<-EOQ
    SELECT n.*
    FROM   nodes n
    WHERE  n.parent_id = 5
    AND EXISTS (SELECT 1
                FROM   nodes n2
                WHERE  ....)
EOQ

Возможно, вы могли бы также заставить все работать, нарисуя внутреннюю таблицу:

current_node.children.where(
  Node.from("nodes n").where("...").select("1").exists
)

Ответ 3

Возможно, вы сможете использовать атрибут table_alias, который вы можете вызвать в таблице Arel::.

Пример:

# works
users = User.arel_table
some_other_table = Post.arel_table
users.table_alias = 'people'
users.join(some_other_table)

# doesn't work
users = User.arel_table.alias('people')
some_other_table = Post.arel_table
users.join(some_other_table)