Пользовательский фильтр Activeadmin не работает - PullRequest
0 голосов
/ 13 ноября 2018

В activeadmin нам нужно применить некий сложный фильтр на индексной странице нашей модели Score. А именно, мы хотим получить результаты в таблице Score, чтобы их ExportOrder имели выбранный DistributionChain. Начнем со следующих моделей:

class Score < ApplicationRecord
  has_and_belongs_to_many :export_orders, join_table: :scores_export_orders
end

class ExportOrder < ApplicationRecord
  belongs_to :distribution_chain
  has_and_belongs_to_many :scores, join_table: :scores_export_orders
end

class DistributionChain < ApplicationRecord
  has_many :export_orders
end

В schema.rb (отрывок):

  create_table "scores_export_orders", id: false, force: :cascade do |t|
    t.integer "score_id"
    t.integer "export_order_id"
    t.index ["export_order_id"], name: "index_scores_export_orders_on_export_order_id", using: :btree
    t.index ["score_id"], name: "index_scores_export_orders_on_score_id", using: :btree
  end

  create_table "export_orders", force: :cascade do |t|
    t.integer  "distribution_chain_id"
  end

В баллах Activeadmin:

ActiveAdmin.register Score
  filter :delivery_distr_chain, as: :select, collection: DistributionChain.all
end

Область действия фильтра определяется в модели оценки:

class Score < ApplicationRecord
  ...
  scope :delivery_distr_chain, -> (input) {
    self.joins(:export_orders).where('export_orders.distribution_chain_id = ?', input)
  }

  def self.ransackable_scopes(auth_object = nil)
    [:delivery_distr_chain]
  end
end

Ниже приведена ошибка:

ActionView::Template::Error (PG::DuplicateAlias: ERROR:  table name "scores_export_orders" specified more than once
: SELECT COUNT(DISTINCT count_column) FROM (SELECT  DISTINCT "scores"."id" AS count_column FROM "scores" INNER JOIN "scores_export_orders" ON "scores_export_orders"."score_id" = "scores"."id" INNER JOIN "export_orders" ON "export_orders"."id" = "scores_export_orders"."export_order_id" LEFT JOIN scores_export_orders ON scores.id = scores_export_orders.score_id WHERE (NOT (scores_export_orders.score_id IS NULL)) AND (export_orders.distribution_chain_id = '2') LIMIT $1 OFFSET $2) subquery_for_count):
    1: insert_tag renderer_for(:index)

activerecord (5.0.7) lib/active_record/connection_adapters/postgresql_adapter.rb:600:in `async_exec'

Я чувствую, что запрос написан неправильно. Можете ли вы сказать нам, где мы терпим неудачу?


РЕДАКТИРОВАТЬ: интересно отметить разницу между выполнением запроса в консоли рельсов и в области действия в модели Score.

Если я выполняю тот же запрос в консоли rails, он работает без ошибок. Выход Score.joins(:export_orders).where('export_orders.distribution_chain_id = ?', '2').to_sql:

"SELECT \"scores\".* FROM \"scores\" INNER JOIN \"scores_export_orders\" ON \"scores_export_orders\".\"score_id\" = \"scores\".\"id\" INNER JOIN \"export_orders\" ON \"export_orders\".\"id\" = \"scores_export_orders\".\"export_order_id\" WHERE (export_orders.distribution_chain_id = '2') ORDER BY \"scores\".\"created_at\" DESC"

, тогда как точно такой же запрос не выполняется в области действия в модели Score, а вывод .to_sql:

"SELECT DISTINCT \"scores\".* FROM \"scores\" INNER JOIN \"scores_export_orders\" ON \"scores_export_orders\".\"score_id\" = \"scores\".\"id\" INNER JOIN \"export_orders\" ON \"export_orders\".\"id\" = \"scores_export_orders\".\"export_order_id\" LEFT JOIN scores_export_orders ON scores.id = scores_export_orders.score_id WHERE (NOT (scores_export_orders.score_id IS NULL)) AND (export_orders.distribution_chain_id = '2') ORDER BY \"scores\".\"id\" desc"

Основное отличие заключается в левом соединении, введенном областью действия: LEFT JOIN scores_export_orders ON scores.id = scores_export_orders.score_id, которое позволяет еще раз указать таблицу scores_export_orders. Я понятия не имею, почему это вводится там, а не на консоли ...

1 Ответ

0 голосов
/ 15 ноября 2018

решаемая.Мне не было известно о том факте, что я уже объявил область действия в своем ActiveAdmin for Scores, которая была следующей:

scope :exported, -> { joins("LEFT JOIN scores_export_orders ON scores.id = scores_export_orders.score_id").where.not("scores_export_orders.score_id IS NULL").distinct

, вызываемой в ActiveAdmin как

  controller do
    def scoped_collection
      end_of_association_chain.exported
    end
    ...
  end

Теперь я переписал код так, чтобы он был в моей модели партитуры:

class Score < ApplicationRecord
  ...
  scope :exported, -> { joins("INNER JOIN scores_export_orders ON scores.id = scores_export_orders.score_id INNER JOIN export_orders ON export_orders.id = scores_export_orders.export_order_id").where.not("scores_export_orders.score_id IS NULL").distinct }
  ...
  scope :delivery_distr_chain, -> (input) {
    self.where('export_orders.distribution_chain_id = ?', input)
  }

  def self.ransackable_scopes(auth_object = nil)
    [:delivery_distr_chain]
  end
end

, чтобы у меня было двойное соединение в области exported, и мне не нужноснова присоединитесь к области фильтра.

...