Skip to content

Commit 71088e8

Browse files
authored
Merge pull request #39 from SValkanov/add_option_for_nested_resource_path_params
Add option to pass path params for nested resource fetching
2 parents 621f6e0 + dff7a08 commit 71088e8

File tree

6 files changed

+200
-3
lines changed

6 files changed

+200
-3
lines changed

README.md

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,67 @@ argument:
242242
end
243243
```
244244

245+
#### Path options for nested resources
246+
247+
Example for the following setup:
248+
249+
```ruby
250+
# Models
251+
class OptionType < ActiveRecord::Base; end
252+
253+
class OptionValue < ActiveRecord::Base
254+
belongs_to :option_type
255+
end
256+
257+
class Product < ActiveRecord::Base
258+
belongs_to :option_type
259+
has_many :variants
260+
end
261+
262+
class Variant < ActiveRecord::Base
263+
belongs_to :product
264+
belongs_to :option_value
265+
end
266+
267+
# ActiveAdmin
268+
ActiveAdmin.register(OptionType)
269+
270+
ActiveAdmin.register(Product)
271+
272+
ActiveAdmin.register(OptionValue) do
273+
belongs_to :option_type
274+
searchable_select_options(scope: lambda do |params|
275+
OptionValue.where(
276+
option_type_id: params[:option_type_id]
277+
)
278+
end,
279+
text_attribute: :value)
280+
end
281+
```
282+
283+
It is possible to pass path parameters for correctly generating URLs for nested resources fetching via `path_params`
284+
285+
```ruby
286+
ActiveAdmin.register(Variant) do
287+
belongs_to :product
288+
289+
form do |f|
290+
...
291+
f.input(:option_value,
292+
as: :searchable_select,
293+
ajax: {
294+
resource: OptionValue,
295+
path_params: {
296+
option_type_id: f.object.product.option_type_id
297+
}
298+
})
299+
...
300+
end
301+
end
302+
```
303+
304+
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`)
305+
245306
#### Inlining Ajax Options in Feature Tests
246307

247308
When writing UI driven feature specs (i.e. with Capybara),
@@ -265,7 +326,7 @@ for feature specs:
265326

266327
### Passing options to Select2
267328

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

271332
Attributes need to be added to the `input_html` option in the form input.

lib/activeadmin/searchable_select/select_input_extension.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ module SearchableSelect
2020
# - `params`: Hash of query parameters that shall be passed to the
2121
# options endpoint.
2222
#
23+
# - `path_params`: Hash of parameters, which would be passed to the
24+
# dynamic collection path generation for the resource.
25+
# e.g `admin_articles_path(path_params)`
26+
#
2327
# If the `ajax` option is present, the `collection` option is
2428
# ignored.
2529
module SelectInputExtension
@@ -45,7 +49,7 @@ def collection_from_options
4549

4650
def ajax_url
4751
return unless options[:ajax]
48-
[ajax_resource.route_collection_path,
52+
[ajax_resource.route_collection_path(path_params),
4953
'/',
5054
option_collection.collection_action_name,
5155
'?',
@@ -124,6 +128,10 @@ def ajax_params
124128
ajax_options.fetch(:params, {})
125129
end
126130

131+
def path_params
132+
ajax_options.fetch(:path_params, {})
133+
end
134+
127135
def ajax_options
128136
options[:ajax] == true ? {} : options[:ajax]
129137
end

spec/features/end_to_end_spec.rb

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

97+
context 'class with nested belongs_to association' do
98+
before(:all) 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+
ajax: {
122+
resource: OptionValue,
123+
path_params: {
124+
option_type_id: f.object.product.option_type_id
125+
}
126+
})
127+
end
128+
end
129+
130+
ActiveAdmin.setup {}
131+
end
132+
end
133+
134+
describe 'new page with searchable select filter' do
135+
it 'loads filter input options' do
136+
option_type = OptionType.create(name: 'Color')
137+
ot = OptionType.create(name: 'Size')
138+
OptionValue.create(value: 'Black', option_type: option_type)
139+
OptionValue.create(value: 'Orange', option_type: option_type)
140+
OptionValue.create(value: 'M', option_type: ot)
141+
product = Product.create(name: 'Cap', option_type: option_type)
142+
143+
visit "/admin/products/#{product.id}/variants/new"
144+
145+
expand_select_box
146+
wait_for_ajax
147+
148+
expect(select_box_items).to eq(%w(Black Orange))
149+
end
150+
151+
it 'allows filtering options by term' do
152+
option_type = OptionType.create(name: 'Color')
153+
ot = OptionType.create(name: 'Size')
154+
OptionValue.create(value: 'Black', option_type: option_type)
155+
OptionValue.create(value: 'Orange', option_type: option_type)
156+
OptionValue.create(value: 'M', option_type: ot)
157+
product = Product.create(name: 'Cap', option_type: option_type)
158+
159+
visit "/admin/products/#{product.id}/variants/new"
160+
161+
expand_select_box
162+
enter_search_term('O')
163+
wait_for_ajax
164+
165+
expect(select_box_items).to eq(%w(Orange))
166+
end
167+
168+
it 'loads more items when scrolling down' do
169+
option_type = OptionType.create(name: 'Color')
170+
15.times { |i| OptionValue.create(value: "Black #{i}", option_type: option_type) }
171+
product = Product.create(name: 'Cap', option_type: option_type)
172+
173+
visit "/admin/products/#{product.id}/variants/new"
174+
175+
expand_select_box
176+
wait_for_ajax
177+
scroll_select_box_list
178+
wait_for_ajax
179+
180+
expect(select_box_items.size).to eq(15)
181+
end
182+
end
183+
end
184+
97185
def expand_select_box
98186
find('.select2-container').click
99187
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: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
module ActiveAdminHelpers
22
module_function
33

4+
def reload_routes!
5+
Rails.application.reload_routes!
6+
end
7+
48
def setup
59
ActiveAdmin.application = nil
610
yield
7-
Rails.application.reload_routes!
11+
reload_routes!
812
end
913
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)