mycowriter 0.1.5 → 0.1.7
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 +4 -4
- data/CHANGELOG.md +33 -0
- data/app/controllers/mycowriter/autocomplete_controller.rb +43 -6
- data/lib/mycowriter/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 39c5a2d07b1a5b470a372a3164de8055d040d75a2dc0688b89ddc00312b182ac
|
|
4
|
+
data.tar.gz: 28b25751676dfd32ebd30605a7431a7a6572bbaa31fea296a2414372d8ce15fb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a5ba7679b9d27b760637e7becfa3bf91f1820d4fe29fb587b2e32f446bf734481778a5e837b0ed4e48797b2bd709dade21fe45d3f0b950862f0837e71d3b5af7
|
|
7
|
+
data.tar.gz: e2dfde5dd18f9d103e91a13a12436a09163653d1a600834802cbbb5ef7ac93f48571a5c6ac29b29a30f7904cd69ed9eb0112f7ab2b99bc6b2df598166733f387
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,39 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.1.7] - 2026-02-21
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **CRITICAL:** Fixed SQL method compatibility - replaced deprecated `sanitize_sql_for_order` with `Arel.sql` + `sanitize_sql_array`
|
|
12
|
+
- Resolves `NoMethodError: undefined method 'sanitize_sql_for_order'` error in Rails 8.0+
|
|
13
|
+
- All ORDER BY clauses now use proper Rails SQL injection protection pattern
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
- Added `genus_name` parameter to species endpoint for inline autocomplete filtering
|
|
17
|
+
- Species autocomplete now filters by preceding genus name (e.g., "Ganoderma sess" → only Ganoderma species)
|
|
18
|
+
- Supports both mushroom form context (`mushroom_id` parameter) and inline text context (`genus_name` parameter)
|
|
19
|
+
|
|
20
|
+
### Technical Details
|
|
21
|
+
- Changed from `Model.connection.sanitize_sql_for_order([...])` to `Arel.sql(Model.sanitize_sql_array([...]))`
|
|
22
|
+
- Applied fix to genera, species, and mb_lists fallback methods
|
|
23
|
+
- Maintains backward compatibility - existing `mushroom_id` filtering still works
|
|
24
|
+
- New `genus_name` parameter is optional and takes precedence over `mushroom_id` when both present
|
|
25
|
+
|
|
26
|
+
## [0.1.6] - 2026-02-21
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
- **CRITICAL:** Fixed autocomplete result ranking to prioritize best matches over alphabetical order
|
|
30
|
+
- Exact matches now appear first, then prefix matches, then substring matches
|
|
31
|
+
- Example: typing "sess" now shows "sessile" at top of results instead of 12th position after alphabetical entries
|
|
32
|
+
- Applied smart ranking to genera autocomplete, species autocomplete, and mb_lists fallback methods
|
|
33
|
+
- Resolves issue where large genus datasets (e.g., 394 Ganoderma species) buried relevant matches deep in alphabetical lists
|
|
34
|
+
|
|
35
|
+
### Technical Details
|
|
36
|
+
- Replaced simple alphabetical `ORDER BY name` with CASE-based priority ranking
|
|
37
|
+
- Priority order: 1=exact match, 2=prefix match, 3=substring match, within each group: alphabetical
|
|
38
|
+
- Uses `sanitize_sql_for_order` for SQL injection protection
|
|
39
|
+
- Maintains backward compatibility - same JSON API contract, no breaking changes
|
|
40
|
+
|
|
8
41
|
## [0.1.1] - 2025-02-20
|
|
9
42
|
|
|
10
43
|
### Changed
|
|
@@ -11,7 +11,14 @@ module Mycowriter
|
|
|
11
11
|
::Genus
|
|
12
12
|
.where("name LIKE ?", "#{::Genus.sanitize_sql_like(query)}%")
|
|
13
13
|
.select(:id, :name)
|
|
14
|
-
.order(
|
|
14
|
+
.order(
|
|
15
|
+
Arel.sql(
|
|
16
|
+
::Genus.sanitize_sql_array([
|
|
17
|
+
"CASE WHEN LOWER(name) = LOWER(?) THEN 1 ELSE 2 END, name",
|
|
18
|
+
query
|
|
19
|
+
])
|
|
20
|
+
)
|
|
21
|
+
)
|
|
15
22
|
.limit(Mycowriter.results_limit)
|
|
16
23
|
.map { |g| { id: g.id, name: g.name } }
|
|
17
24
|
else
|
|
@@ -24,18 +31,23 @@ module Mycowriter
|
|
|
24
31
|
render json: results
|
|
25
32
|
end
|
|
26
33
|
|
|
27
|
-
# GET /mycowriter/autocomplete/species.json?q=placo&mushroom_id=1
|
|
34
|
+
# GET /mycowriter/autocomplete/species.json?q=placo&mushroom_id=1&genus_name=Ganoderma
|
|
28
35
|
def species
|
|
29
36
|
query = params[:q].to_s.strip
|
|
30
37
|
mushroom_id = params[:mushroom_id]
|
|
38
|
+
genus_name = params[:genus_name]
|
|
31
39
|
|
|
32
40
|
results = if query.length >= Mycowriter.min_characters
|
|
33
41
|
# Check if the host app has a Species model
|
|
34
42
|
if defined?(::Species)
|
|
35
43
|
scope = ::Species.where("name LIKE ?", "%#{::Species.sanitize_sql_like(query)}%")
|
|
36
44
|
|
|
37
|
-
# Filter by
|
|
38
|
-
if
|
|
45
|
+
# Filter by genus name (for inline autocomplete)
|
|
46
|
+
if genus_name.present? && defined?(::Genus)
|
|
47
|
+
genus = ::Genus.find_by(name: genus_name)
|
|
48
|
+
scope = scope.where(genera_id: genus.id) if genus
|
|
49
|
+
# OR filter by selected genera for this mushroom (for mushroom form)
|
|
50
|
+
elsif mushroom_id.present? && defined?(::Mushroom)
|
|
39
51
|
mushroom = ::Mushroom.find_by(id: mushroom_id)
|
|
40
52
|
if mushroom && mushroom.respond_to?(:genera) && mushroom.genera.any?
|
|
41
53
|
genera_ids = mushroom.genera.pluck(:id)
|
|
@@ -44,10 +56,23 @@ module Mycowriter
|
|
|
44
56
|
end
|
|
45
57
|
|
|
46
58
|
# Use includes to eager load genera and avoid N+1 queries
|
|
59
|
+
# Smart ranking: exact matches first, then prefix matches, then substring matches
|
|
47
60
|
species_results = scope
|
|
48
61
|
.includes(:genus)
|
|
49
62
|
.select(:id, :name, :genera_id)
|
|
50
|
-
.order(
|
|
63
|
+
.order(
|
|
64
|
+
Arel.sql(
|
|
65
|
+
::Species.sanitize_sql_array([
|
|
66
|
+
"CASE
|
|
67
|
+
WHEN LOWER(name) = LOWER(?) THEN 1
|
|
68
|
+
WHEN LOWER(name) LIKE LOWER(?) THEN 2
|
|
69
|
+
ELSE 3
|
|
70
|
+
END, name",
|
|
71
|
+
query,
|
|
72
|
+
"#{query}%"
|
|
73
|
+
])
|
|
74
|
+
)
|
|
75
|
+
)
|
|
51
76
|
.limit(Mycowriter.results_limit)
|
|
52
77
|
|
|
53
78
|
species_results.map do |sp|
|
|
@@ -87,7 +112,19 @@ module Mycowriter
|
|
|
87
112
|
|
|
88
113
|
scope
|
|
89
114
|
.select(:id, :taxon_name)
|
|
90
|
-
.order(
|
|
115
|
+
.order(
|
|
116
|
+
Arel.sql(
|
|
117
|
+
::MbList.sanitize_sql_array([
|
|
118
|
+
"CASE
|
|
119
|
+
WHEN LOWER(taxon_name) = LOWER(?) THEN 1
|
|
120
|
+
WHEN LOWER(taxon_name) LIKE LOWER(?) THEN 2
|
|
121
|
+
ELSE 3
|
|
122
|
+
END, taxon_name",
|
|
123
|
+
query,
|
|
124
|
+
"#{query}%"
|
|
125
|
+
])
|
|
126
|
+
)
|
|
127
|
+
)
|
|
91
128
|
.limit(Mycowriter.results_limit)
|
|
92
129
|
.map { |m| { id: m.id, name: m.taxon_name } }
|
|
93
130
|
end
|
data/lib/mycowriter/version.rb
CHANGED