tam_select 1.0.0 → 1.1.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e3f063f1d79268f900b10c4b86399cba1a34dac0154a90c4c12fd505771a1431
4
- data.tar.gz: 0cf4fe7a1cf1d1dc479065318819db1ced4e71888e81e6c98a25fc6920841852
3
+ metadata.gz: 3cdee3c229caaeda5d7f572395009c1ffd03e58c1f5376c215ced0e751c35fb9
4
+ data.tar.gz: 9896dd22aa1dc9af3727596c1bee1d82ca6b8f1462a3e24a5177b10306853888
5
5
  SHA512:
6
- metadata.gz: 8ad40f38121d3e83e9260c825c8bbd7546c62d87073fef14ef63c70fd027a1a08bcbd18d51d60198d3a06410b2e3c3ffd325182f99b9b08c1af7b23e725a70c3
7
- data.tar.gz: 55469f46c8348ed51dff78070efe3ddf8b95ce43cb2ae3d5b299382bf80437022fe1f91066e07c2b4d061abfba0c984d892d958616692a02415c062e4cb622db
6
+ metadata.gz: 271d3b88383037c504189080665c0c15e19a640e6f8efe0d580683d9f543a0a56ff496a667064b788fbd8a8f1ddc8f48512d755cfc10985ec043d36c042891ce
7
+ data.tar.gz: be82081ad386749cb1ff40f1cd48ca80417104712c417de25dccc969082f3f2edfce09a912bce53467c34e170b1a0235245caede8d53717b7fff5d3b21d8f072
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  the # Tam Select
2
2
 
3
3
  [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
4
- [![Gem Version](https://img.shields.io/badge/version-0.1.1-blue.svg)](https://github.com/tamiru/tam_select)
4
+ [![Gem Version](https://img.shields.io/badge/version-1.1.0-blue.svg)](https://github.com/tamiru/tam_select)
5
5
 
6
6
  **Tam Select** is an accessible, searchable select component for Ruby on Rails, built for Simple Form, Stimulus, Turbo, and Tailwind CSS. It keeps the native `<select>` as the source of truth, so Rails form submission, validation, selected values, and browser autofill continue to work.
7
7
 
@@ -36,6 +36,7 @@ app/javascript/tam_select/tam_select.js
36
36
  app/javascript/controllers/tam_select_controller.js
37
37
  app/inputs/tam_select_input.rb
38
38
  app/controllers/concerns/tam_select_paginatable.rb
39
+ app/controllers/concerns/tam_select_remote.rb
39
40
  app/controllers/tam_select_remote_controller.rb
40
41
  app/helpers/tam_select_helper.rb
41
42
  ```
@@ -131,7 +132,9 @@ Stimulus destroys generated markup when Turbo removes the select and recreates i
131
132
 
132
133
  ## Simple Form
133
134
 
134
- The install generator creates `app/inputs/tam_select_input.rb`. Use it like any other Simple Form input:
135
+ The install generator creates `app/inputs/tam_select_input.rb`. Use `as: :tam_select` with any Simple Form collection input.
136
+
137
+ ### Local collection
135
138
 
136
139
  ```erb
137
140
  <%= form.input :region_id,
@@ -139,16 +142,49 @@ The install generator creates `app/inputs/tam_select_input.rb`. Use it like any
139
142
  collection: Region.order(:name),
140
143
  label_method: :name,
141
144
  value_method: :id,
145
+ prompt: "Select region" %>
146
+ ```
147
+
148
+ ### Remote collection
149
+
150
+ Keep the currently selected record in the initial collection so edit forms can display its label before the AJAX request completes:
151
+
152
+ ```erb
153
+ <%= form.input :region_id,
154
+ as: :tam_select,
155
+ collection: [form.object.region].compact,
156
+ label_method: :name,
157
+ value_method: :id,
142
158
  prompt: "Select region",
143
159
  input_html: {
144
160
  tam_options: {
145
- remoteUrl: region_options_path(format: :json),
146
- minQueryLength: 1
161
+ remoteUrl: tam_select_options_regions_path(format: :json),
162
+ minQueryLength: 1,
163
+ debounce: 250
147
164
  }
148
165
  } %>
149
166
  ```
150
167
 
151
- For a many-to-many field, add `multiple: true` to `input_html`.
168
+ The concern and route required by this example are described in [Add remote search to an existing controller](#add-remote-search-to-an-existing-controller).
169
+
170
+ ### Multiple selection
171
+
172
+ ```erb
173
+ <%= form.input :skill_ids,
174
+ as: :tam_select,
175
+ collection: Skill.order(:name),
176
+ label_method: :name,
177
+ value_method: :id,
178
+ input_html: {
179
+ multiple: true,
180
+ tam_options: {
181
+ searchable: true,
182
+ closeAfterSelect: false
183
+ }
184
+ } %>
185
+ ```
186
+
187
+ Options are passed under `input_html[:tam_options]`. Common options include `searchable`, `creatable`, `clearable`, `placeholder`, `searchPlaceholder`, `remoteUrl`, `minQueryLength`, and `debounce`. See [Main options](#main-options) for defaults.
152
188
 
153
189
  ## Remote API contract
154
190
 
@@ -172,6 +208,53 @@ The generator installs `TamSelectPaginatable` as a Rails response helper. A comp
172
208
 
173
209
  Secure remote endpoints exactly like other Rails JSON endpoints. Scope records by the current user's permissions and never trust a submitted value merely because it appeared in the dropdown.
174
210
 
211
+ ### Add remote search to an existing controller
212
+
213
+ Include `TamSelectRemote` and declare the allowed model and searchable fields. This adds the public `tam_select_options` action to the controller:
214
+
215
+ ```ruby
216
+ # app/controllers/regions_controller.rb
217
+ class RegionsController < ApplicationController
218
+ include TamSelectRemote
219
+
220
+ tam_select_remote(
221
+ model: Region,
222
+ label: :name,
223
+ value: :id,
224
+ search_by: %i[name code],
225
+ scope: -> { Region.order(:name) },
226
+ per_page: 20
227
+ )
228
+ end
229
+ ```
230
+
231
+ The optional `scope` lambda runs in the controller context, so it can use `current_user`, `current_account`, or an authorization policy.
232
+
233
+ ```ruby
234
+ # config/routes.rb
235
+ resources :regions do
236
+ get :tam_select_options, on: :collection, defaults: { format: :json }
237
+ end
238
+ ```
239
+
240
+ Point Simple Form to that collection action:
241
+
242
+ ```erb
243
+ <%= form.input :region_id,
244
+ as: :tam_select,
245
+ collection: [form.object.region].compact,
246
+ label_method: :name,
247
+ value_method: :id,
248
+ input_html: {
249
+ tam_options: {
250
+ remoteUrl: tam_select_options_regions_path(format: :json),
251
+ minQueryLength: 1
252
+ }
253
+ } %>
254
+ ```
255
+
256
+ Typing sends `GET /regions/tam_select_options.json?q=addis&page=1` and receives the standard Tam Select JSON payload.
257
+
175
258
  ### Generic remote controller
176
259
 
177
260
  The installer generates `TamSelectRemoteController`. Create a small subclass for each allowed remote source:
@@ -18,6 +18,7 @@ module TamSelect
18
18
 
19
19
  def copy_controller_concern
20
20
  copy_file "lib/generators/tam_select/templates/tam_select_paginatable.rb", "app/controllers/concerns/tam_select_paginatable.rb"
21
+ copy_file "lib/generators/tam_select/templates/tam_select_remote.rb", "app/controllers/concerns/tam_select_remote.rb"
21
22
  end
22
23
 
23
24
  def copy_remote_controller
@@ -0,0 +1,54 @@
1
+ module TamSelectRemote
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ include TamSelectPaginatable
6
+ class_attribute :tam_select_remote_config, instance_writer: false
7
+ end
8
+
9
+ class_methods do
10
+ def tam_select_remote(model:, label:, value: :id, search_by: nil, scope: nil, per_page: 20)
11
+ self.tam_select_remote_config = {
12
+ model: model,
13
+ label: label,
14
+ value: value,
15
+ search_by: Array(search_by || label),
16
+ scope: scope,
17
+ per_page: per_page
18
+ }.freeze
19
+ end
20
+ end
21
+
22
+ def tam_select_options
23
+ config = tam_select_remote_config!
24
+ records = tam_select_remote_search(tam_select_remote_scope(config), config)
25
+
26
+ render json: tam_select_payload(
27
+ records,
28
+ label: config[:label],
29
+ value: config[:value],
30
+ per_page: config[:per_page]
31
+ )
32
+ end
33
+
34
+ private
35
+
36
+ def tam_select_remote_config!
37
+ self.class.tam_select_remote_config ||
38
+ raise("Configure #{self.class.name} with tam_select_remote(...)")
39
+ end
40
+
41
+ def tam_select_remote_scope(config)
42
+ config[:scope] ? instance_exec(&config[:scope]) : config[:model].all
43
+ end
44
+
45
+ def tam_select_remote_search(records, config)
46
+ query = params[:q].to_s.strip
47
+ return records if query.blank?
48
+
49
+ model = config[:model]
50
+ pattern = "%#{model.sanitize_sql_like(query)}%"
51
+ predicates = config[:search_by].map { |field| model.arel_table[field].matches(pattern) }
52
+ records.where(predicates.reduce(&:or))
53
+ end
54
+ end
@@ -1,44 +1,6 @@
1
1
  class TamSelectRemoteController < ApplicationController
2
- include TamSelectPaginatable
2
+ include TamSelectRemote
3
3
 
4
- class_attribute :tam_select_config, instance_writer: false
5
-
6
- def self.tam_select(model:, label:, value: :id, search_by: nil, per_page: 20)
7
- self.tam_select_config = {
8
- model: model,
9
- label: label,
10
- value: value,
11
- search_by: Array(search_by || label),
12
- per_page: per_page
13
- }.freeze
14
- end
15
-
16
- def index
17
- config = self.class.tam_select_config
18
- raise "Configure #{self.class.name} with tam_select(...)" unless config
19
-
20
- records = search(tam_select_scope(config), config)
21
- render json: tam_select_payload(
22
- records,
23
- label: config[:label],
24
- value: config[:value],
25
- per_page: config[:per_page]
26
- )
27
- end
28
-
29
- private
30
-
31
- def tam_select_scope(config)
32
- config[:model].all
33
- end
34
-
35
- def search(records, config)
36
- query = params[:q].to_s.strip
37
- return records if query.blank?
38
-
39
- model = config[:model]
40
- pattern = "%#{model.sanitize_sql_like(query)}%"
41
- predicates = config[:search_by].map { |field| model.arel_table[field].matches(pattern) }
42
- records.where(predicates.reduce(&:or))
43
- end
4
+ # Configure this base controller in a subclass, or include TamSelectRemote
5
+ # directly in an existing resource controller. See the Tam Select README.
44
6
  end
@@ -1,3 +1,3 @@
1
1
  module TamSelect
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1.1"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tam_select
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tamiru Hailu
@@ -62,6 +62,7 @@ files:
62
62
  - lib/generators/tam_select/templates/tam_select_helper.rb
63
63
  - lib/generators/tam_select/templates/tam_select_input.rb
64
64
  - lib/generators/tam_select/templates/tam_select_paginatable.rb
65
+ - lib/generators/tam_select/templates/tam_select_remote.rb
65
66
  - lib/generators/tam_select/templates/tam_select_remote_controller.rb
66
67
  - lib/tam_select.rb
67
68
  - lib/tam_select/engine.rb