Рельсы/Арел: выберите сумму случая вместе с моделью

#ruby-on-rails #ruby #arel

Вопрос:

У меня есть модель под названием Post (таблица posts ), которая связана с моделью под названием User (таблица users ), на которую в модели Post ссылаются как на «загрузчика» (в таблице posts есть столбец uploader_id , который называется id «пользователи таблицы»). У пользователя может быть много записей, некоторые из которых могут быть удалены (помечены в is_deleted логическом столбце posts ).

Как мне получить список пользователей с указанием общего количества и удаленных сообщений?

 ::Post
  .select(
    Arel.star.count.as("total"),
    Arel::Nodes::Case.new.when(Post.arel_table[:is_deleted]).then(1).sum.as("deleted_count"),
    :uploader
   )
  .joins(:uploader)
  .group(:uploader)
  .order(:total, :deleted_count)
  .limit(20)
 

Это не работает. Мне нужно, чтобы пользователь был возвращен в качестве модели, идентификатора uploader_id недостаточно.

Я пробовал много попыток сделать это, но что бы я ни делал, я не могу этого понять. Либо он пытается вставить «#

Что меня крайне расстраивает, так это то, что вместо этого это работает, если мне нужно только общее количество сообщений и пользователь:

 ::Post
  .joins(:uploader)
  .group(:uploader)
  .order(Arel.sql("count(*) desc"))
  .limit(20)
  .count
 

Я просто не могу понять, как добавить сумму условного случая, я новичок в rails, и документация не помогает.

Ответ №1:

«Как мне получить список пользователей с количеством общих и удаленных сообщений?», похоже, вы идете в неверном направлении. Лучше начать User с того, что вы хотите User , чтобы объекты возвращались.

Также Post.arel_table[:is_deleted] не является условием, которым это должно быть Post.arel_table[:is_deleted].eq(1) , или что-то «истинное» в вашей базе данных.

Вместо этого попробуйте выполнить следующее:

 User.left_joins(:posts)
  .select(
     User.arel_table[Arel.star],
     Post.arel_table[Arel.star].count.as('total_posts'),
     Arel::Nodes::Case.new 
       .when(Post.arel_table[:is_deleted].eq(1)).then(1)
       .else(0).sum.as('deleted_count'))
  .group(:id)
  .order(
    Post.arel_table[Arel.star].count, 
    Arel::Nodes::Case.new 
      .when(Post.arel_table[:is_deleted].eq(1)).then(1)
      .else(0).sum)
  .limit(20)
 

Комментарии:

1. Хороший ответ. Если вы используете Postgres, вы можете использовать count(posts.*) filter where is_deleted вместо заявления о случае.

2. @макс очень милый. К сожалению, одно из мест Arel не подходит. В то время как я не удосужился попробовать в данный момент (хотя в какой-то момент, вероятно, я это сделаю) Я не могу себе представить, насколько запутанным будет выглядеть это выражение, написанное с помощью Arel объектов.