Skip to content

Commit ecf5b97

Browse files
committed
Merge pull request activeadmin#1563 from gregbell/fix-collections-with-group-by
Fix collections with group by
2 parents 3130933 + da6e448 commit ecf5b97

File tree

10 files changed

+249
-71
lines changed

10 files changed

+249
-71
lines changed

features/index/index_scopes.feature

Lines changed: 105 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,31 @@ Feature: Index Scoping
33
Viewing resources and scoping them
44

55
Scenario: Viewing resources with one scope and no default
6-
Given 10 posts exist
6+
Given 3 posts exist
77
And an index configuration of:
88
"""
99
ActiveAdmin.register Post do
1010
scope :all
1111
end
1212
"""
1313
Then I should see the scope "All" not selected
14-
And I should see the scope "All" with the count 10
15-
And I should see 10 posts in the table
14+
And I should see the scope "All" with the count 3
15+
And I should see 3 posts in the table
1616

1717
Scenario: Viewing resources with one scope as the default
18-
Given 10 posts exist
18+
Given 3 posts exist
1919
And an index configuration of:
2020
"""
2121
ActiveAdmin.register Post do
2222
scope :all, :default => true
2323
end
2424
"""
2525
Then I should see the scope "All" selected
26-
And I should see the scope "All" with the count 10
27-
And I should see 10 posts in the table
26+
And I should see the scope "All" with the count 3
27+
And I should see 3 posts in the table
2828

2929
Scenario: Viewing resources with one scope and no results
30-
Given 10 posts exist
30+
Given 3 posts exist
3131
And an index configuration of:
3232
"""
3333
ActiveAdmin.register Post do
@@ -36,15 +36,15 @@ Feature: Index Scoping
3636
end
3737
"""
3838

39-
When I fill in "Search Title" with "Hello World 17"
39+
When I fill in "Search Title" with "Non Existing Post"
4040
And I press "Filter"
4141
And I should not see the scope "All"
4242

4343
When I am on the index page for posts
4444
Then I should see the scope "All" selected
4545

4646
Scenario: Viewing resources with a scope but scope_count turned off
47-
Given 10 posts exist
47+
Given 3 posts exist
4848
And an index configuration of:
4949
"""
5050
ActiveAdmin.register Post do
@@ -54,11 +54,11 @@ Feature: Index Scoping
5454
"""
5555
Then I should see the scope "All" selected
5656
And I should see the scope "All" with no count
57-
And I should see 10 posts in the table
57+
And I should see 3 posts in the table
5858

5959
@scope
6060
Scenario: Viewing resources with a scope and scope count turned off for a single scope
61-
Given 10 posts exist
61+
Given 3 posts exist
6262
And an index configuration of:
6363
"""
6464
ActiveAdmin.register Post do
@@ -67,11 +67,11 @@ Feature: Index Scoping
6767
"""
6868
Then I should see the scope "All" selected
6969
And I should see the scope "All" with no count
70-
And I should see 10 posts in the table
70+
And I should see 3 posts in the table
7171

7272
Scenario: Viewing resources when scoping
73-
Given 6 posts exist
74-
And 4 published posts exist
73+
Given 2 posts exist
74+
And 3 published posts exist
7575
And an index configuration of:
7676
"""
7777
ActiveAdmin.register Post do
@@ -81,15 +81,49 @@ Feature: Index Scoping
8181
end
8282
end
8383
"""
84-
Then I should see the scope "All" with the count 10
85-
And I should see 10 posts in the table
86-
Then I should see the scope "Published" with the count 4
84+
Then I should see the scope "All" with the count 5
85+
And I should see 5 posts in the table
86+
And I should see the scope "Published" with the count 3
8787
When I follow "Published"
8888
Then I should see the scope "Published" selected
89-
And I should see 4 posts in the table
89+
And I should see 3 posts in the table
90+
91+
Scenario: Viewing resources when scoping and filtering
92+
Given 2 posts written by "Daft Punk" exist
93+
Given 1 published posts written by "Daft Punk" exist
94+
95+
Given 1 posts written by "Alfred" exist
96+
Given 2 published posts written by "Alfred" exist
97+
98+
And an index configuration of:
99+
"""
100+
ActiveAdmin.register Post do
101+
scope :all, :default => true
102+
scope :published do |posts|
103+
posts.where("published_at IS NOT NULL")
104+
end
105+
end
106+
"""
107+
Then I should see the scope "All" with the count 6
108+
And I should see the scope "Published" with the count 3
109+
And I should see 6 posts in the table
110+
111+
When I follow "Published"
112+
Then I should see the scope "Published" selected
113+
And I should see the scope "All" with the count 6
114+
And I should see the scope "Published" with the count 3
115+
And I should see 3 posts in the table
116+
117+
When I select "daft_punk" from "Author"
118+
And I press "Filter"
119+
120+
Then I should see the scope "Published" selected
121+
And I should see the scope "All" with the count 3
122+
And I should see the scope "Published" with the count 1
123+
And I should see 1 posts in the table
90124

91125
Scenario: Viewing resources with optional scopes
92-
Given 10 posts exist
126+
Given 3 posts exist
93127
And an index configuration of:
94128
"""
95129
ActiveAdmin.register Post do
@@ -109,10 +143,10 @@ Feature: Index Scoping
109143
And I should not see the scope "All"
110144
And I should not see the scope "Today"
111145
And I should see the scope "Shown"
112-
And I should see the scope "Default" with the count 10
146+
And I should see the scope "Default" with the count 3
113147

114148
Scenario: Viewing resources with multiple scopes as blocks
115-
Given 10 posts exist
149+
Given 3 posts exist
116150
And an index configuration of:
117151
"""
118152
ActiveAdmin.register Post do
@@ -126,17 +160,17 @@ Feature: Index Scoping
126160
"""
127161
Then I should see the scope "Today" selected
128162
And I should see the scope "Tomorrow" not selected
129-
And I should see the scope "Today" with the count 10
163+
And I should see the scope "Today" with the count 3
130164
And I should see the scope "Tomorrow" with the count 0
131-
And I should see 10 posts in the table
165+
And I should see 3 posts in the table
132166
And I should see a link to "Tomorrow"
133167

134168
When I follow "Tomorrow"
135169
Then I should see the scope "Tomorrow" selected
136170
And I should see the scope "Today" not selected
137171
And I should see a link to "Today"
138172

139-
Scenario: Viewing resources with scopes when a filter is applied
173+
Scenario: Viewing resources with scopes when scoping to user
140174
Given 2 posts written by "Daft Punk" exist
141175
And a post with the title "Monkey Wrench" written by "Foo Fighters" exists
142176
And a post with the title "Everlong" written by "Foo Fighters" exists
@@ -145,6 +179,7 @@ Feature: Index Scoping
145179
ActiveAdmin.register Post do
146180
scope_to :current_user
147181
scope :all, :default => true
182+
148183
filter :title
149184
150185
controller do
@@ -160,3 +195,49 @@ Feature: Index Scoping
160195
And I press "Filter"
161196
Then I should see the scope "All" not selected
162197
And I should see the scope "All" with the count 1
198+
199+
Scenario: Viewing resources when scoping and filtering and group bys and stuff
200+
Given 2 posts written by "Daft Punk" exist
201+
Given 1 published posts written by "Daft Punk" exist
202+
203+
Given 1 posts written by "Alfred" exist
204+
205+
And an index configuration of:
206+
"""
207+
ActiveAdmin.register Post do
208+
scope :all, :default => true
209+
scope :published do |posts|
210+
posts.where("published_at IS NOT NULL")
211+
end
212+
213+
index do
214+
column :author_id
215+
column :count
216+
end
217+
218+
config.sort_order = "author_id_asc"
219+
220+
controller do
221+
def scoped_collection
222+
Post.select("author_id, count(*) as count").group("author_id")
223+
end
224+
end
225+
end
226+
"""
227+
Then I should see the scope "All" with the count 2
228+
And I should see the scope "Published" with the count 1
229+
And I should see 2 posts in the table
230+
231+
When I follow "Published"
232+
Then I should see the scope "Published" selected
233+
And I should see the scope "All" with the count 2
234+
And I should see the scope "Published" with the count 1
235+
And I should see 1 posts in the table
236+
237+
When I select "daft_punk" from "Author"
238+
And I press "Filter"
239+
240+
Then I should see the scope "Published" selected
241+
And I should see the scope "All" with the count 1
242+
And I should see the scope "Published" with the count 1
243+
And I should see 1 posts in the table

features/step_definitions/factory_steps.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@
1313
Post.create! :title => title, :author => author, :published_at => published_at
1414
end
1515

16-
Given /^(\d+) posts? written by "([^"]*)" exist$/ do |count, author_name|
16+
Given /^(\d+)( published)? posts? written by "([^"]*)" exist$/ do |count, published, author_name|
1717
first, last = author_name.split(' ')
1818
author = User.find_or_create_by_first_name_and_last_name(first, last, :username => author_name.gsub(' ', '').underscore)
1919
(0...count.to_i).each do |i|
20-
Post.create! :title => "Hello World #{i}", :author => author
20+
Post.create! :title => "Hello World #{i}", :author => author, :published_at => (published ? Time.now : nil)
2121
end
2222
end
2323

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
module ActiveAdmin
2+
module Helpers
3+
module Collection
4+
# Works around this issue: https://github.com/rails/rails/issues/7121
5+
#
6+
# GROUP BY + COUNT drops SELECT statement. This leads to SQL error when
7+
# the ORDER statement mentions a column defined in the SELECT statement.
8+
#
9+
# We remove the ORDER statement to work around this issue.
10+
def collection_size(collection=collection)
11+
size = collection.reorder("").count
12+
# when GROUP BY is used, AR returns Hash instead of Fixnum for .size
13+
size = size.size if size.kind_of?(Hash)
14+
15+
size
16+
end
17+
18+
def collection_is_empty?(collection=collection)
19+
collection_size(collection) == 0
20+
end
21+
end
22+
end
23+
end

lib/active_admin/resource_controller/collection.rb

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,17 +88,20 @@ def active_admin_collection
8888
end
8989

9090
def scope_current_collection(chain)
91+
@collection_before_scope = chain
92+
9193
if current_scope
92-
@before_scope_collection = chain
9394
scope_chain(current_scope, chain)
94-
elsif active_admin_config.scope_to
95-
@before_scope_collection = scoped_collection
96-
chain
9795
else
9896
chain
9997
end
10098
end
10199

100+
def collection_before_scope
101+
@collection_before_scope
102+
end
103+
104+
102105
include ActiveAdmin::ScopeChain
103106

104107
def current_scope

lib/active_admin/views/components/paginated_collection.rb

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
require 'active_admin/helpers/collection'
2+
13
module ActiveAdmin
24
module Views
35

@@ -85,12 +87,14 @@ def build_download_format_links(formats = [:csv, :xml, :json])
8587
end
8688
end
8789

90+
include ::ActiveAdmin::Helpers::Collection
91+
8892
# modified from will_paginate
8993
def page_entries_info(options = {})
9094
if options[:entry_name]
9195
entry_name = options[:entry_name]
9296
entries_name = options[:entries_name] || entry_name.pluralize
93-
elsif collection.empty?
97+
elsif collection_is_empty?
9498
entry_name = I18n.translate("active_admin.pagination.entry", :count => 1, :default => 'entry')
9599
entries_name = I18n.translate("active_admin.pagination.entry", :count => 2, :default => 'entries')
96100
else
@@ -99,17 +103,15 @@ def page_entries_info(options = {})
99103
end
100104

101105
if collection.num_pages < 2
102-
case collection.size
106+
case collection_size
103107
when 0; I18n.t('active_admin.pagination.empty', :model => entries_name)
104108
when 1; I18n.t('active_admin.pagination.one', :model => entry_name)
105109
else; I18n.t('active_admin.pagination.one_page', :model => entries_name, :n => collection.total_count)
106110
end
107111
else
108-
size = collection.size
109-
size = size.size if size.kind_of? Hash # when GROUP BY is used, AR returns Hash instead of Fixnum for .size
110112
offset = (collection.current_page - 1) * collection.limit_value
111113
total = collection.total_count
112-
I18n.t('active_admin.pagination.multiple', :model => entries_name, :from => offset + 1, :to => offset + size, :total => total)
114+
I18n.t('active_admin.pagination.multiple', :model => entries_name, :from => offset + 1, :to => offset + collection_size, :total => total)
113115
end
114116
end
115117

lib/active_admin/views/components/scopes.rb

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
require 'active_admin/helpers/collection'
2+
13
module ActiveAdmin
24
module Views
35

@@ -7,6 +9,8 @@ class Scopes < ActiveAdmin::Component
79
builder_method :scopes_renderer
810

911
include ActiveAdmin::ScopeChain
12+
include ::ActiveAdmin::Helpers::Collection
13+
1014

1115
def default_class_name
1216
"scopes table_tools_segmented_control"
@@ -54,22 +58,13 @@ def current_scope?(scope)
5458
end
5559

5660
def current_filter_search_empty?
57-
collection.empty? && params.include?(:q)
61+
params.include?(:q) && collection_is_empty?
5862
end
5963

6064
# Return the count for the scope passed in.
6165
def get_scope_count(scope)
62-
if params[:q]
63-
search(scope_chain(scope, scoping_class)).relation.count
64-
else
65-
scope_chain(scope, scoping_class).count
66-
end
66+
collection_size(scope_chain(scope, collection_before_scope))
6767
end
68-
69-
def scoping_class
70-
assigns[:before_scope_collection] || active_admin_config.resource_class
71-
end
72-
7368
end
7469
end
7570
end

0 commit comments

Comments
 (0)