activeadmin-searchable_select 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +10 -0
  5. data/.travis.yml +16 -0
  6. data/.yardopts +2 -0
  7. data/Appraisals +15 -0
  8. data/CHANGELOG.md +7 -0
  9. data/Gemfile +3 -0
  10. data/LICENSE.txt +25 -0
  11. data/README.md +247 -0
  12. data/Rakefile +6 -0
  13. data/activeadmin-searchable_select.gemspec +37 -0
  14. data/app/assets/javascripts/active_admin/searchable_select.js.coffee +3 -0
  15. data/app/assets/javascripts/active_admin/searchable_select/init.js.coffee +29 -0
  16. data/app/assets/stylesheets/active_admin/searchable_select.scss +5 -0
  17. data/bin/rspec +17 -0
  18. data/gemfiles/rails_4.2_active_admin_1.0.0.pre4.gemfile +9 -0
  19. data/gemfiles/rails_5.1_active_admin_1.0.gemfile +8 -0
  20. data/gemfiles/rails_5.1_active_admin_1.1.gemfile +8 -0
  21. data/lib/activeadmin-searchable_select.rb +6 -0
  22. data/lib/activeadmin/inputs/filters/searchable_select_input.rb +13 -0
  23. data/lib/activeadmin/inputs/searchable_select_input.rb +11 -0
  24. data/lib/activeadmin/searchable_select.rb +20 -0
  25. data/lib/activeadmin/searchable_select/engine.rb +11 -0
  26. data/lib/activeadmin/searchable_select/option_collection.rb +103 -0
  27. data/lib/activeadmin/searchable_select/resource_dsl_extension.rb +39 -0
  28. data/lib/activeadmin/searchable_select/resource_extension.rb +10 -0
  29. data/lib/activeadmin/searchable_select/select_input_extension.rb +130 -0
  30. data/lib/activeadmin/searchable_select/version.rb +5 -0
  31. data/spec/features/ajax_params_spec.rb +53 -0
  32. data/spec/features/end_to_end_spec.rb +83 -0
  33. data/spec/features/filter_input_spec.rb +191 -0
  34. data/spec/features/form_input_spec.rb +178 -0
  35. data/spec/features/inline_ajax_setting_spec.rb +41 -0
  36. data/spec/features/input_errors_spec.rb +55 -0
  37. data/spec/features/options_dsl_spec.rb +248 -0
  38. data/spec/internal/app/assets/javascripts/active_admin.js +2 -0
  39. data/spec/internal/app/assets/stylesheets/active_admin.scss +2 -0
  40. data/spec/internal/app/controllers/application_controller.rb +5 -0
  41. data/spec/internal/config/database.yml +3 -0
  42. data/spec/internal/config/initializers/assets.rb +3 -0
  43. data/spec/internal/config/routes.rb +3 -0
  44. data/spec/internal/db/schema.rb +26 -0
  45. data/spec/internal/log/.gitignore +1 -0
  46. data/spec/internal/public/favicon.ico +0 -0
  47. data/spec/rails_helper.rb +13 -0
  48. data/spec/spec_helper.rb +96 -0
  49. data/spec/support/active_admin_helpers.rb +9 -0
  50. data/spec/support/capybara.rb +8 -0
  51. data/spec/support/models.rb +21 -0
  52. data/spec/support/pluck_polyfill.rb +12 -0
  53. data/spec/support/reset_settings.rb +5 -0
  54. metadata +311 -0
@@ -0,0 +1,83 @@
1
+ require 'rails_helper'
2
+
3
+ require 'support/models'
4
+ require 'support/capybara'
5
+ require 'support/active_admin_helpers'
6
+
7
+ RSpec.describe 'end to end', type: :feature, js: true do
8
+ before(:each) do
9
+ ActiveAdminHelpers.setup do
10
+ ActiveAdmin.register(Category) do
11
+ searchable_select_options(scope: Category, text_attribute: :name)
12
+ end
13
+
14
+ ActiveAdmin.register(Post) do
15
+ filter(:category, as: :searchable_select, ajax: true)
16
+
17
+ form do |f|
18
+ f.input(:category, as: :searchable_select, ajax: true)
19
+ end
20
+ end
21
+
22
+ ActiveAdmin.setup {}
23
+ end
24
+ end
25
+
26
+ describe 'index page with searchable select filter' do
27
+ before(:each) do
28
+ music_category = Category.create(name: 'Music')
29
+ travel_category = Category.create(name: 'Travel')
30
+
31
+ Post.create(title: 'Best songs',
32
+ category: music_category)
33
+ Post.create(title: 'Best places',
34
+ category: travel_category)
35
+ end
36
+
37
+ it 'loads filter input options' do
38
+ visit '/admin/posts'
39
+
40
+ expand_select_box
41
+
42
+ expect(select_box_items).to eq(%w(Music Travel))
43
+ end
44
+
45
+ it 'allows filtering options by term' do
46
+ visit '/admin/posts'
47
+
48
+ expand_select_box
49
+
50
+ wait_for_ajax do
51
+ enter_search_term('T')
52
+ end
53
+
54
+ expect(select_box_items).to eq(%w(Travel))
55
+ end
56
+ end
57
+
58
+ def expand_select_box
59
+ find('.select2-container').click
60
+ end
61
+
62
+ def enter_search_term(term)
63
+ find('.select2-dropdown input').send_keys(term)
64
+ end
65
+
66
+ def select_box_items
67
+ all('.select2-dropdown li').map(&:text)
68
+ end
69
+
70
+ def wait_for_ajax(count = 1)
71
+ page.execute_script 'window._ajaxCalls = 0'
72
+ page.execute_script 'window._ajaxCompleteCounter = function() { window._ajaxCalls += 1; }'
73
+ page.execute_script '$(document).ajaxComplete(window._ajaxCompleteCounter)'
74
+
75
+ yield
76
+
77
+ sleep(0.5) until finished_all_ajax_requests?(count)
78
+ end
79
+
80
+ def finished_all_ajax_requests?(count)
81
+ page.evaluate_script('window._ajaxCalls') == count
82
+ end
83
+ end
@@ -0,0 +1,191 @@
1
+ require 'rails_helper'
2
+
3
+ require 'support/models'
4
+ require 'support/capybara'
5
+ require 'support/active_admin_helpers'
6
+
7
+ RSpec.describe 'filter input', type: :request do
8
+ describe 'without ajax option' do
9
+ before(:each) do
10
+ ActiveAdminHelpers.setup do
11
+ ActiveAdmin.register(Post) do
12
+ filter :category, as: :searchable_select
13
+ end
14
+ end
15
+ end
16
+
17
+ it 'renders select input with searchable-select-input css class' do
18
+ get '/admin/posts'
19
+
20
+ expect(response.body).to have_selector('select.searchable-select-input')
21
+ end
22
+
23
+ it 'renders options statically' do
24
+ Category.create!(name: 'Travel')
25
+ Category.create!(name: 'Music')
26
+
27
+ get '/admin/posts'
28
+
29
+ expect(response.body).to have_selector('.searchable-select-input option', text: 'Travel')
30
+ expect(response.body).to have_selector('.searchable-select-input option', text: 'Music')
31
+ end
32
+
33
+ it 'does not set data-ajax-url attribute' do
34
+ get '/admin/posts'
35
+
36
+ expect(response.body).not_to have_selector('.searchable-select-input[data-ajax-url]')
37
+ end
38
+ end
39
+
40
+ shared_examples 'renders ajax based searchable select input' do
41
+ it 'renders select input with searchable-select-input css class' do
42
+ get '/admin/posts'
43
+
44
+ expect(response.body).to have_selector('select.searchable-select-input')
45
+ end
46
+
47
+ it 'does not render options statically' do
48
+ Category.create!(name: 'Travel')
49
+
50
+ get '/admin/posts'
51
+
52
+ expect(response.body).not_to have_selector('.searchable-select-input option', text: 'Travel')
53
+ end
54
+
55
+ it 'sets data-ajax-url attribute' do
56
+ get '/admin/posts'
57
+
58
+ expect(response.body).to have_selector('.searchable-select-input[data-ajax-url]')
59
+ end
60
+
61
+ it 'renders selected option for current value' do
62
+ category = Category.create!(name: 'Travel')
63
+
64
+ get "/admin/posts?q[category_id_eq]=#{category.id}"
65
+
66
+ expect(response.body).to have_selector('.searchable-select-input option[selected]',
67
+ text: 'Travel')
68
+ end
69
+ end
70
+
71
+ describe 'with ajax option set to true' do
72
+ before(:each) do
73
+ ActiveAdminHelpers.setup do
74
+ ActiveAdmin.register(Category) do
75
+ searchable_select_options(scope: Category, text_attribute: :name)
76
+ end
77
+
78
+ ActiveAdmin.register(Post) do
79
+ filter(:category,
80
+ as: :searchable_select,
81
+ ajax: true)
82
+ end
83
+ end
84
+ end
85
+
86
+ include_examples 'renders ajax based searchable select input'
87
+ end
88
+
89
+ describe 'with options collection name passed in ajax option' do
90
+ before(:each) do
91
+ ActiveAdminHelpers.setup do
92
+ ActiveAdmin.register(Category) do
93
+ searchable_select_options(name: 'custom', scope: Category, text_attribute: :name)
94
+ end
95
+
96
+ ActiveAdmin.register(Post) do
97
+ filter(:category,
98
+ as: :searchable_select,
99
+ ajax: {
100
+ collection_name: 'custom'
101
+ })
102
+ end
103
+ end
104
+ end
105
+
106
+ include_examples 'renders ajax based searchable select input'
107
+ end
108
+
109
+ describe 'with options resource passed in ajax option' do
110
+ before(:each) do
111
+ ActiveAdminHelpers.setup do
112
+ ActiveAdmin.register(Category) do
113
+ searchable_select_options(scope: Category, text_attribute: :name)
114
+ end
115
+
116
+ ActiveAdmin.register(Post) do
117
+ filter(:category_id_eq,
118
+ as: :searchable_select,
119
+ ajax: {
120
+ resource: Category
121
+ })
122
+ end
123
+ end
124
+ end
125
+
126
+ include_examples 'renders ajax based searchable select input'
127
+ end
128
+
129
+ describe 'with options resource and collection name passed in ajax option' do
130
+ before(:each) do
131
+ ActiveAdminHelpers.setup do
132
+ ActiveAdmin.register(Category) do
133
+ searchable_select_options(name: 'custom', scope: Category, text_attribute: :name)
134
+ end
135
+
136
+ ActiveAdmin.register(Post) do
137
+ filter(:category_id_eq,
138
+ as: :searchable_select,
139
+ ajax: {
140
+ resource: Category,
141
+ collection_name: 'custom'
142
+ })
143
+ end
144
+ end
145
+ end
146
+
147
+ include_examples 'renders ajax based searchable select input'
148
+ end
149
+
150
+ describe 'with selected option in ajax mode' do
151
+ it 'applies scope when looking up record' do
152
+ ActiveAdminHelpers.setup do
153
+ ActiveAdmin.register(Category) do
154
+ searchable_select_options(scope: Category.none, text_attribute: :name)
155
+ end
156
+
157
+ ActiveAdmin.register(Post) do
158
+ filter(:category, as: :searchable_select, ajax: true)
159
+ end
160
+ end
161
+
162
+ category = Category.create!(name: 'Travel')
163
+
164
+ get "/admin/posts?q[category_id_eq]=#{category.id}"
165
+
166
+ expect(response.body).not_to have_selector('.searchable-select-input option[selected]')
167
+ end
168
+
169
+ it 'allows to use view helpers in scope lambda' do
170
+ ActiveAdminHelpers.setup do
171
+ ActiveAdmin.register(Category) do
172
+ searchable_select_options(scope: -> { Category.where(created_by: current_user) },
173
+ text_attribute: :name)
174
+ end
175
+
176
+ ActiveAdmin.register(Post) do
177
+ filter(:category, as: :searchable_select, ajax: true)
178
+ end
179
+ end
180
+
181
+ user = User.create!
182
+ ApplicationController.current_user = user
183
+ category = Category.create!(name: 'Travel', created_by: user)
184
+
185
+ get "/admin/posts?q[category_id_eq]=#{category.id}"
186
+
187
+ expect(response.body).to have_selector('.searchable-select-input option[selected]',
188
+ text: 'Travel')
189
+ end
190
+ end
191
+ end
@@ -0,0 +1,178 @@
1
+ require 'rails_helper'
2
+
3
+ require 'support/models'
4
+ require 'support/capybara'
5
+ require 'support/active_admin_helpers'
6
+
7
+ RSpec.describe 'form input', type: :request do
8
+ describe 'without ajax option' do
9
+ before(:each) do
10
+ ActiveAdminHelpers.setup do
11
+ ActiveAdmin.register(Post) do
12
+ form do |f|
13
+ f.input :category, as: :searchable_select
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ it 'renders select input with searchable-select-input css class' do
20
+ get '/admin/posts/new'
21
+
22
+ expect(response.body).to have_selector('select.searchable-select-input')
23
+ end
24
+
25
+ it 'renders options statically' do
26
+ Category.create!(name: 'Travel')
27
+ Category.create!(name: 'Music')
28
+
29
+ get '/admin/posts/new'
30
+
31
+ expect(response.body).to have_selector('.searchable-select-input option', text: 'Travel')
32
+ expect(response.body).to have_selector('.searchable-select-input option', text: 'Music')
33
+ end
34
+
35
+ it 'does not set data-ajax-url attribute' do
36
+ get '/admin/posts/new'
37
+
38
+ expect(response.body).not_to have_selector('.searchable-select-input[data-ajax-url]')
39
+ end
40
+ end
41
+
42
+ shared_examples 'renders ajax based searchable select input' do
43
+ it 'renders select input with searchable-select-input css class' do
44
+ get '/admin/posts/new'
45
+
46
+ expect(response.body).to have_selector('select.searchable-select-input')
47
+ end
48
+
49
+ it 'does not render options statically' do
50
+ Category.create!(name: 'Travel')
51
+
52
+ get '/admin/posts/new'
53
+
54
+ expect(response.body).not_to have_selector('.searchable-select-input option', text: 'Travel')
55
+ end
56
+
57
+ it 'sets data-ajax-url attribute' do
58
+ get '/admin/posts/new'
59
+
60
+ expect(response.body).to have_selector('.searchable-select-input[data-ajax-url]')
61
+ end
62
+
63
+ it 'renders selected option for current value' do
64
+ category = Category.create!(name: 'Travel')
65
+ post = Post.create!(title: 'A post', category: category)
66
+
67
+ get "/admin/posts/#{post.id}/edit"
68
+
69
+ expect(response.body).to have_selector('.searchable-select-input option[selected]',
70
+ text: 'Travel')
71
+ end
72
+ end
73
+
74
+ describe 'with ajax option set to true' do
75
+ before(:each) do
76
+ ActiveAdminHelpers.setup do
77
+ ActiveAdmin.register(Category) do
78
+ searchable_select_options(scope: Category, text_attribute: :name)
79
+ end
80
+
81
+ ActiveAdmin.register(Post) do
82
+ form do |f|
83
+ f.input(:category,
84
+ as: :searchable_select,
85
+ ajax: true)
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ include_examples 'renders ajax based searchable select input'
92
+ end
93
+
94
+ describe 'with options collection name passed in ajax option' do
95
+ before(:each) do
96
+ ActiveAdminHelpers.setup do
97
+ ActiveAdmin.register(Category) do
98
+ searchable_select_options(name: 'custom', scope: Category, text_attribute: :name)
99
+ end
100
+
101
+ ActiveAdmin.register(Post) do
102
+ form do |f|
103
+ f.input(:category,
104
+ as: :searchable_select,
105
+ ajax: {
106
+ collection_name: 'custom'
107
+ })
108
+ end
109
+ end
110
+ end
111
+ end
112
+
113
+ include_examples 'renders ajax based searchable select input'
114
+ end
115
+
116
+ describe 'with options resource passed in ajax option' do
117
+ before(:each) do
118
+ ActiveAdminHelpers.setup do
119
+ ActiveAdmin.register(Category) do
120
+ searchable_select_options(scope: Category, text_attribute: :name)
121
+ end
122
+
123
+ ActiveAdmin.register(Post) do
124
+ form do |f|
125
+ f.input(:category_id,
126
+ as: :searchable_select,
127
+ ajax: {
128
+ resource: Category
129
+ })
130
+ end
131
+ end
132
+ end
133
+ end
134
+
135
+ include_examples 'renders ajax based searchable select input'
136
+ end
137
+
138
+ describe 'with options resource and collection name passed in ajax option' do
139
+ before(:each) do
140
+ ActiveAdminHelpers.setup do
141
+ ActiveAdmin.register(Category) do
142
+ searchable_select_options(name: 'custom', scope: Category, text_attribute: :name)
143
+ end
144
+
145
+ ActiveAdmin.register(Post) do
146
+ form do |f|
147
+ f.input(:category_id,
148
+ as: :searchable_select,
149
+ ajax: {
150
+ resource: Category,
151
+ collection_name: 'custom'
152
+ })
153
+ end
154
+ end
155
+ end
156
+ end
157
+
158
+ include_examples 'renders ajax based searchable select input'
159
+ end
160
+
161
+ describe 'with custom class attribute' do
162
+ before(:each) do
163
+ ActiveAdminHelpers.setup do
164
+ ActiveAdmin.register(Post) do
165
+ form do |f|
166
+ f.input :category, as: :searchable_select, input_html: { class: 'custom' }
167
+ end
168
+ end
169
+ end
170
+ end
171
+
172
+ it 'adds searchable-select-input css class' do
173
+ get '/admin/posts/new'
174
+
175
+ expect(response.body).to have_selector('select.custom.searchable-select-input')
176
+ end
177
+ end
178
+ end