Skip to content

Commit e0f0804

Browse files
committed
Add option to pass path params for nested resource fetching
1 parent ac15d4f commit e0f0804

File tree

6 files changed

+188
-3
lines changed

6 files changed

+188
-3
lines changed

README.md

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ for feature specs:
265265

266266
### Passing options to Select2
267267

268-
It is possible to pass and define configuration options to Select2
268+
It is possible to pass and define configuration options to Select2
269269
via `data-attributes` using nested (subkey) options.
270270

271271
Attributes need to be added to the `input_html` option in the form input.
@@ -285,6 +285,65 @@ has stopped typing before sending the request:
285285
...
286286
```
287287

288+
### Path options for nested resources
289+
290+
Example for the following setup:
291+
292+
```ruby
293+
# Models
294+
class OptionType < ActiveRecord::Base; end
295+
296+
class OptionValue < ActiveRecord::Base
297+
belongs_to :option_type
298+
end
299+
300+
class Product < ActiveRecord::Base
301+
belongs_to :option_type
302+
has_many :variants
303+
end
304+
305+
class Variant < ActiveRecord::Base
306+
belongs_to :product
307+
belongs_to :option_value
308+
end
309+
310+
# ActiveAdmin
311+
ActiveAdmin.register(OptionType)
312+
313+
ActiveAdmin.register(Product)
314+
315+
ActiveAdmin.register(OptionValue) do
316+
belongs_to :option_type
317+
searchable_select_options(scope: lambda do |params|
318+
OptionValue.where(
319+
option_type_id: params[:option_type_id]
320+
)
321+
end,
322+
text_attribute: :value)
323+
end
324+
```
325+
326+
It is possible to pass path parameters for correctly generating URLs for nested resources fetching via `path_params`
327+
328+
```ruby
329+
ActiveAdmin.register(Variant) do
330+
belongs_to :product
331+
332+
form do |f|
333+
...
334+
f.input(:option_value,
335+
as: :searchable_select,
336+
path_params: {
337+
option_type_id: f.object.product.option_type_id
338+
},
339+
ajax: { resource: OptionValue })
340+
...
341+
end
342+
end
343+
```
344+
345+
This will generate the path for fetching as `all_options_admin_option_type_option_values(option_type_id: f.object.product.option_type_id)` (e.g. `/admin/option_types/2/option_values/all_options`)
346+
288347

289348
## Development
290349

lib/activeadmin/searchable_select/select_input_extension.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def collection_from_options
4545

4646
def ajax_url
4747
return unless options[:ajax]
48-
[ajax_resource.route_collection_path,
48+
[ajax_resource.route_collection_path(path_params),
4949
'/',
5050
option_collection.collection_action_name,
5151
'?',
@@ -124,6 +124,10 @@ def ajax_params
124124
ajax_options.fetch(:params, {})
125125
end
126126

127+
def path_params
128+
options[:path_params]
129+
end
130+
127131
def ajax_options
128132
options[:ajax] == true ? {} : options[:ajax]
129133
end

spec/features/end_to_end_spec.rb

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,92 @@
9494
end
9595
end
9696

97+
context 'class with nested belongs_to association' do
98+
before(:each) do
99+
ActiveAdminHelpers.setup do
100+
ActiveAdmin.register(OptionType)
101+
102+
ActiveAdmin.register(Product)
103+
104+
ActiveAdmin.register(OptionValue) do
105+
belongs_to :option_type
106+
searchable_select_options(scope: lambda do |params|
107+
OptionValue.where(
108+
option_type_id: params[:option_type_id]
109+
)
110+
end,
111+
text_attribute: :value)
112+
end
113+
114+
ActiveAdmin.register(Variant) do
115+
belongs_to :product
116+
117+
form do |f|
118+
input :price
119+
input(:option_value,
120+
as: :searchable_select,
121+
path_params: { option_type_id: f.object.product.option_type_id },
122+
ajax: {
123+
resource: OptionValue
124+
})
125+
end
126+
end
127+
128+
ActiveAdmin.setup {}
129+
end
130+
end
131+
132+
describe 'new page with searchable select filter' do
133+
it 'loads filter input options' do
134+
option_type = OptionType.create(name: 'Color')
135+
ot = OptionType.create(name: 'Size')
136+
OptionValue.create(value: 'Black', option_type: option_type)
137+
OptionValue.create(value: 'Orange', option_type: option_type)
138+
OptionValue.create(value: 'M', option_type: ot)
139+
product = Product.create(name: 'Cap', option_type: option_type)
140+
141+
visit "/admin/products/#{product.id}/variants/new"
142+
143+
expand_select_box
144+
wait_for_ajax
145+
146+
expect(select_box_items).to eq(%w(Black Orange))
147+
end
148+
149+
it 'allows filtering options by term' do
150+
option_type = OptionType.create(name: 'Color')
151+
ot = OptionType.create(name: 'Size')
152+
OptionValue.create(value: 'Black', option_type: option_type)
153+
OptionValue.create(value: 'Orange', option_type: option_type)
154+
OptionValue.create(value: 'M', option_type: ot)
155+
product = Product.create(name: 'Cap', option_type: option_type)
156+
157+
visit "/admin/products/#{product.id}/variants/new"
158+
159+
expand_select_box
160+
enter_search_term('O')
161+
wait_for_ajax
162+
163+
expect(select_box_items).to eq(%w(Orange))
164+
end
165+
166+
it 'loads more items when scrolling down' do
167+
option_type = OptionType.create(name: 'Color')
168+
15.times { |i| OptionValue.create(value: "Black #{i}", option_type: option_type) }
169+
product = Product.create(name: 'Cap', option_type: option_type)
170+
171+
visit "/admin/products/#{product.id}/variants/new"
172+
173+
expand_select_box
174+
wait_for_ajax
175+
scroll_select_box_list
176+
wait_for_ajax
177+
178+
expect(select_box_items.size).to eq(15)
179+
end
180+
end
181+
end
182+
97183
def expand_select_box
98184
find('.select2-container').click
99185
end

spec/internal/db/schema.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,26 @@
3131
t.integer :color_id
3232
end
3333

34+
create_table(:option_types, force: true) do |t|
35+
t.string :name
36+
end
37+
38+
create_table(:option_values, force: true) do |t|
39+
t.string :value
40+
t.belongs_to :option_type
41+
end
42+
43+
create_table(:products, force: true) do |t|
44+
t.string :name
45+
t.belongs_to :option_type
46+
end
47+
48+
create_table(:variants, force: true) do |t|
49+
t.integer :price
50+
t.belongs_to :product
51+
t.belongs_to :option_value
52+
end
53+
3454
create_table(:users, force: true) do |t|
3555
t.string :name
3656
end

spec/support/active_admin_helpers.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ module ActiveAdminHelpers
22
module_function
33

44
def setup
5-
ActiveAdmin.application = nil
5+
ActiveAdmin.unload!
66
yield
77
Rails.application.reload_routes!
88
end

spec/support/models.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,22 @@ class TagName < ActiveRecord::Base
2727
end
2828
end
2929

30+
class OptionType < ActiveRecord::Base; end
31+
32+
class OptionValue < ActiveRecord::Base
33+
belongs_to :option_type
34+
end
35+
36+
class Product < ActiveRecord::Base
37+
belongs_to :option_type
38+
has_many :variants
39+
end
40+
41+
class Variant < ActiveRecord::Base
42+
belongs_to :product
43+
belongs_to :option_value
44+
end
45+
3046
RSpec.configure do |config|
3147
config.after do
3248
DatabaseCleaner.strategy = :truncation

0 commit comments

Comments
 (0)