Activeadmin 自定义过滤器失败
Activeadmin custom filter fails
在activeadmin中,我们需要在Score模型的索引页上应用一种复杂的过滤器。即,我们希望在 Score
table 中获得结果,以便他们的 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.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 OFFSET ) 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'
我感觉查询没有写好。你能告诉我们我们在哪里失败了吗?
编辑: 有趣的是在 rails 控制台中执行查询与在 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
table。我不知道为什么这是在那里介绍而不是在控制台上...
已解决。我不知道我已经在我的 ActiveAdmin 中为 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
范围内进行双重连接,而无需在过滤范围内再次连接。
在activeadmin中,我们需要在Score模型的索引页上应用一种复杂的过滤器。即,我们希望在 Score
table 中获得结果,以便他们的 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.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 OFFSET ) 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'
我感觉查询没有写好。你能告诉我们我们在哪里失败了吗?
编辑: 有趣的是在 rails 控制台中执行查询与在 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
table。我不知道为什么这是在那里介绍而不是在控制台上...
已解决。我不知道我已经在我的 ActiveAdmin 中为 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
范围内进行双重连接,而无需在过滤范围内再次连接。