Activeadmin custom filter fails
In activeadmin, we need to apply a kind of complicated filter on the index page of our Score model. Namely, we want to get the results in the Score table such that their ExportOrders have the selected DistributionChain. We start from the following models:
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
In the schema.rb (excerpt):
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
In Score Activeadmin:
ActiveAdmin.register Score
filter :delivery_distr_chain, as: :select, collection: DistributionChain.all
end
The scope of the filter is defined in the score model:
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
Following is the error:
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'
I sense that the query is not properly written. Can you tell us where we are failing?
EDIT: interesting to notice is the difference between executing the query in the rails console and within the scope in the Score model.
If I execute the same query in the rails console, it works without errors. The output of Score.joins(:export_orders).where('export_orders.distribution_chain_id = ?', '2').to_sql is:
"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"
whereas the exact same query fails in the scope in the Score model, and the .to_sql output is:
"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"
The main difference lies in the left-join introduced by the scope: LEFT JOIN scores_export_orders ON scores.id = scores_export_orders.score_id, which lets specify the scores_export_orders table once more. I have no idea why this is introduced in there and not on the console...
sql ruby-on-rails postgresql filter activeadmin
add a comment |
In activeadmin, we need to apply a kind of complicated filter on the index page of our Score model. Namely, we want to get the results in the Score table such that their ExportOrders have the selected DistributionChain. We start from the following models:
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
In the schema.rb (excerpt):
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
In Score Activeadmin:
ActiveAdmin.register Score
filter :delivery_distr_chain, as: :select, collection: DistributionChain.all
end
The scope of the filter is defined in the score model:
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
Following is the error:
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'
I sense that the query is not properly written. Can you tell us where we are failing?
EDIT: interesting to notice is the difference between executing the query in the rails console and within the scope in the Score model.
If I execute the same query in the rails console, it works without errors. The output of Score.joins(:export_orders).where('export_orders.distribution_chain_id = ?', '2').to_sql is:
"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"
whereas the exact same query fails in the scope in the Score model, and the .to_sql output is:
"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"
The main difference lies in the left-join introduced by the scope: LEFT JOIN scores_export_orders ON scores.id = scores_export_orders.score_id, which lets specify the scores_export_orders table once more. I have no idea why this is introduced in there and not on the console...
sql ruby-on-rails postgresql filter activeadmin
add a comment |
In activeadmin, we need to apply a kind of complicated filter on the index page of our Score model. Namely, we want to get the results in the Score table such that their ExportOrders have the selected DistributionChain. We start from the following models:
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
In the schema.rb (excerpt):
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
In Score Activeadmin:
ActiveAdmin.register Score
filter :delivery_distr_chain, as: :select, collection: DistributionChain.all
end
The scope of the filter is defined in the score model:
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
Following is the error:
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'
I sense that the query is not properly written. Can you tell us where we are failing?
EDIT: interesting to notice is the difference between executing the query in the rails console and within the scope in the Score model.
If I execute the same query in the rails console, it works without errors. The output of Score.joins(:export_orders).where('export_orders.distribution_chain_id = ?', '2').to_sql is:
"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"
whereas the exact same query fails in the scope in the Score model, and the .to_sql output is:
"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"
The main difference lies in the left-join introduced by the scope: LEFT JOIN scores_export_orders ON scores.id = scores_export_orders.score_id, which lets specify the scores_export_orders table once more. I have no idea why this is introduced in there and not on the console...
sql ruby-on-rails postgresql filter activeadmin
In activeadmin, we need to apply a kind of complicated filter on the index page of our Score model. Namely, we want to get the results in the Score table such that their ExportOrders have the selected DistributionChain. We start from the following models:
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
In the schema.rb (excerpt):
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
In Score Activeadmin:
ActiveAdmin.register Score
filter :delivery_distr_chain, as: :select, collection: DistributionChain.all
end
The scope of the filter is defined in the score model:
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
Following is the error:
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'
I sense that the query is not properly written. Can you tell us where we are failing?
EDIT: interesting to notice is the difference between executing the query in the rails console and within the scope in the Score model.
If I execute the same query in the rails console, it works without errors. The output of Score.joins(:export_orders).where('export_orders.distribution_chain_id = ?', '2').to_sql is:
"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"
whereas the exact same query fails in the scope in the Score model, and the .to_sql output is:
"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"
The main difference lies in the left-join introduced by the scope: LEFT JOIN scores_export_orders ON scores.id = scores_export_orders.score_id, which lets specify the scores_export_orders table once more. I have no idea why this is introduced in there and not on the console...
sql ruby-on-rails postgresql filter activeadmin
sql ruby-on-rails postgresql filter activeadmin
edited Nov 14 '18 at 16:43
Simon
asked Nov 13 '18 at 18:55
SimonSimon
313214
313214
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
Solved. I was not aware of the fact that I already declare a scope in my ActiveAdmin for Scores, which was the following:
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
called in ActiveAdmin as
controller do
def scoped_collection
end_of_association_chain.exported
end
...
end
Now I've rewritten the code such that I have in my score model:
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
so that I have the double join on the exported scope and I don't need to join again on the filter scope.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53287766%2factiveadmin-custom-filter-fails%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
Solved. I was not aware of the fact that I already declare a scope in my ActiveAdmin for Scores, which was the following:
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
called in ActiveAdmin as
controller do
def scoped_collection
end_of_association_chain.exported
end
...
end
Now I've rewritten the code such that I have in my score model:
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
so that I have the double join on the exported scope and I don't need to join again on the filter scope.
add a comment |
Solved. I was not aware of the fact that I already declare a scope in my ActiveAdmin for Scores, which was the following:
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
called in ActiveAdmin as
controller do
def scoped_collection
end_of_association_chain.exported
end
...
end
Now I've rewritten the code such that I have in my score model:
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
so that I have the double join on the exported scope and I don't need to join again on the filter scope.
add a comment |
Solved. I was not aware of the fact that I already declare a scope in my ActiveAdmin for Scores, which was the following:
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
called in ActiveAdmin as
controller do
def scoped_collection
end_of_association_chain.exported
end
...
end
Now I've rewritten the code such that I have in my score model:
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
so that I have the double join on the exported scope and I don't need to join again on the filter scope.
Solved. I was not aware of the fact that I already declare a scope in my ActiveAdmin for Scores, which was the following:
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
called in ActiveAdmin as
controller do
def scoped_collection
end_of_association_chain.exported
end
...
end
Now I've rewritten the code such that I have in my score model:
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
so that I have the double join on the exported scope and I don't need to join again on the filter scope.
answered Nov 15 '18 at 13:26
SimonSimon
313214
313214
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53287766%2factiveadmin-custom-filter-fails%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown