rails-simple-search 1.1.10 → 1.2.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 +4 -4
- data/README.md +69 -3
- data/lib/sql_handler.rb +36 -15
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 163e11eed3a64c95ca420d49bd6ade5d62bfeaeaff693b3b9586a387f89b7ae1
|
4
|
+
data.tar.gz: adb762be25ea2e2672d400667764728ca051df3dba97604610f4a5fe43f7d64b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d5f332112cbb55e5d966c4d0bba3044a19f56b0923ccc7f256b59fdcdee2d0e83d3708db5ffc718910b7fbe241c3f6480e5503be02ceb967603443ae5942dff7
|
7
|
+
data.tar.gz: 765ce655040b6488cb7137fa56afdc9fa3abcee70ca718f6972e0a9f8317ccb794cef9834b071638fc5a96689a22a217fd09c894787ba7d970b6df9a4a0b7ad1
|
data/README.md
CHANGED
@@ -1,10 +1,30 @@
|
|
1
|
+
[](https://badge.fury.io/rb/rails-simple-search)
|
2
|
+
|
3
|
+
### Table of Contents
|
4
|
+
|
5
|
+
* [What is rails-simple-search?](#what-is-rails-simple-search)
|
6
|
+
|
7
|
+
* [Why rails-simple-search?](#why-rails-simple-search)
|
8
|
+
|
9
|
+
* [Installation](#installation)
|
10
|
+
|
11
|
+
* [Usage](#usage)
|
12
|
+
|
13
|
+
* [How to construct field names](#how-to-construct-field-names)
|
14
|
+
|
15
|
+
* [Demo projects](#demo-projects)
|
16
|
+
|
17
|
+
* [Version history](#version-history)
|
18
|
+
|
19
|
+
* [License](#license)
|
20
|
+
|
1
21
|
## What is rails-simple-search?
|
2
22
|
rails-simple-search is a Ruby gem. It can help Ruby on Rails developers **quickly**
|
3
23
|
implement searching/filtering function against database. If you're not looking
|
4
24
|
for a full-text searching solution, this plugin will most probably **satisfy all**
|
5
25
|
your searching requirement.
|
6
26
|
|
7
|
-
## Why?
|
27
|
+
## Why rails-simple-search?
|
8
28
|
From time to time, I need to build pages to show a list of narrowed down records
|
9
29
|
from a database table by giving some searching criteria on some columns of the
|
10
30
|
table and/or of some referencing tables. Before I implemented this plugin, I usually
|
@@ -67,6 +87,8 @@ The following is how we implement this searching function with rails-simple-sear
|
|
67
87
|
```
|
68
88
|
|
69
89
|
4. Code in views:
|
90
|
+
**Pay attention to the name of the form fields**.
|
91
|
+
|
70
92
|
```
|
71
93
|
<% form_for @search, url => "/xxxxxx", data: {turbo: false} do |f| %>
|
72
94
|
|
@@ -89,7 +111,7 @@ The following is how we implement this searching function with rails-simple-sear
|
|
89
111
|
<%=f.text_field "address.city" %> <!-- address is an association of model User -->
|
90
112
|
|
91
113
|
<%=f.label "name of any one who commented to my posts" %>
|
92
|
-
<%=f.text_field "posts.comments.
|
114
|
+
<%=f.text_field "posts.comments.user.first_name_or_posts.comments.user.last_name" %>
|
93
115
|
<!-- the associations could go even deeper, isn't it POWERFUL? -->
|
94
116
|
|
95
117
|
<%=f.submit %>
|
@@ -105,6 +127,50 @@ The following is how we implement this searching function with rails-simple-sear
|
|
105
127
|
post "/xxxxxx" => "yyyyyyy#zzzzzz"
|
106
128
|
```
|
107
129
|
|
130
|
+
## How to construct field names
|
131
|
+
1. Let's call the model we're search for is the base model. If you just want to search
|
132
|
+
against any direct fields of the base model, we just use the table field name as the html
|
133
|
+
input field name. For example
|
134
|
+
```
|
135
|
+
"email"
|
136
|
+
```
|
137
|
+
|
138
|
+
2. If you need to search against fields of the base model's association, you can just
|
139
|
+
use the association name and the table field name with a dot "." connecting them. Like this
|
140
|
+
```
|
141
|
+
"address.city"
|
142
|
+
```
|
143
|
+
|
144
|
+
3. You can chain the associations more than 2 layers. For example, we're going to
|
145
|
+
find out the users whose posts have been commented by someone whose first name we happen to know.
|
146
|
+
```
|
147
|
+
"posts.comments.user.first_name"
|
148
|
+
```
|
149
|
+
|
150
|
+
4. Sometimes we need to find out something according to a range of time, or a range of numbers,
|
151
|
+
we can attach "_greater_than", "_greater_than_equal_to", "_less_than", or "_less_than_equal_to".
|
152
|
+
For example, we need to find out the users who birth date is between a range, the field names
|
153
|
+
can be like this
|
154
|
+
```
|
155
|
+
birth_date_greater_than
|
156
|
+
```
|
157
|
+
and
|
158
|
+
```
|
159
|
+
birth_date_greater_than
|
160
|
+
```
|
161
|
+
|
162
|
+
5. Sometimes we need to express the idea of "or", for example, I know roughly a user's name, but
|
163
|
+
not sure if it's her first name or last name, we can do it like this
|
164
|
+
```
|
165
|
+
first_name_or_last_name
|
166
|
+
```
|
167
|
+
|
168
|
+
6. We can even use the "or" relation with association fields. For example
|
169
|
+
```
|
170
|
+
posts.comments.user.first_name_or_posts.comments.user.last_name
|
171
|
+
```
|
172
|
+
|
173
|
+
|
108
174
|
## Demo projects
|
109
175
|
There are 2 demo projects for this gem, one for [Rails 5](https://github.com/yzhanginwa/demo_app_for_rails_simple_search)
|
110
176
|
and one for [Rails 7](https://github.com/yzhanginwa/rails_simple_search_demo). You are encouraged to clone them to your local and
|
@@ -122,7 +188,7 @@ From version 1.1.0 on, we started to support the "or" relation, e.g., we can use
|
|
122
188
|
|
123
189
|
From version 1.1.3 on, we started to support Rails 5.
|
124
190
|
|
125
|
-
For Rails 7, please use version 1.
|
191
|
+
For Rails 7, please use version 1.2.0.
|
126
192
|
|
127
193
|
## License
|
128
194
|
|
data/lib/sql_handler.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module RailsSimpleSearch
|
2
2
|
module SqlHandler
|
3
3
|
def init
|
4
|
-
@
|
4
|
+
@model_table_name = @model_class.table_name
|
5
5
|
@joins = {}
|
6
6
|
end
|
7
7
|
|
@@ -36,7 +36,7 @@ module RailsSimpleSearch
|
|
36
36
|
joins.each do |j|
|
37
37
|
table = j[1]
|
38
38
|
constrain = j[2]
|
39
|
-
@joins_str << " inner join #{table} on #{constrain}"
|
39
|
+
@joins_str << format(" inner join #{table} AS A%02d on #{constrain}", j[0])
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
@@ -45,16 +45,17 @@ module RailsSimpleSearch
|
|
45
45
|
@condition_group.set_relation(:and)
|
46
46
|
|
47
47
|
@criteria.each do |key, value|
|
48
|
-
@condition_group.add(
|
48
|
+
@condition_group.add(parse_search_parameters(key, value))
|
49
49
|
end
|
50
50
|
|
51
51
|
make_joins
|
52
52
|
end
|
53
53
|
|
54
|
-
def
|
54
|
+
def build_single_condition(base_class, association_alias, field, value)
|
55
55
|
field, operator = parse_field_name(field)
|
56
56
|
table = base_class.table_name
|
57
57
|
key = "#{table}.#{field}"
|
58
|
+
final_key = "#{association_alias}.#{field}"
|
58
59
|
|
59
60
|
column = base_class.columns_hash[field.to_s]
|
60
61
|
return nil unless column
|
@@ -65,17 +66,22 @@ module RailsSimpleSearch
|
|
65
66
|
verb = 'in'
|
66
67
|
elsif operator
|
67
68
|
verb = operator
|
68
|
-
elsif text_column?(column) && ! @config[:exact_match].include?((@
|
69
|
+
elsif text_column?(column) && ! @config[:exact_match].include?((@model_table_name == table) ? field : key)
|
69
70
|
verb = 'like'
|
70
71
|
value = "%#{value}%"
|
71
72
|
else
|
72
73
|
verb = '='
|
73
74
|
end
|
74
75
|
|
75
|
-
ConditionGroup.new(ConditionItem.new(
|
76
|
+
ConditionGroup.new(ConditionItem.new(final_key, verb, value))
|
76
77
|
end
|
77
78
|
|
78
|
-
def
|
79
|
+
def table_name_to_alias(table_name)
|
80
|
+
format('A%02d', @joins[table_name][0])
|
81
|
+
end
|
82
|
+
|
83
|
+
def insert_join(base_class, asso_ref, new_asso_chain)
|
84
|
+
debugger
|
79
85
|
base_table = base_class.table_name
|
80
86
|
asso_table = asso_ref.klass.table_name
|
81
87
|
|
@@ -84,45 +90,57 @@ module RailsSimpleSearch
|
|
84
90
|
return unless @joins[asso_table].nil?
|
85
91
|
|
86
92
|
@join_count += 1
|
93
|
+
base_table_alias = new_asso_chain ? base_table : table_name_to_alias(base_table)
|
94
|
+
asso_table_alias = format('A%02d', @join_count)
|
95
|
+
|
87
96
|
if asso_ref.belongs_to?
|
88
|
-
@joins[asso_table] =[@join_count, asso_table, "#{
|
97
|
+
@joins[asso_table] =[@join_count, asso_table, "#{base_table_alias}.#{asso_ref.foreign_key} = #{asso_table_alias}.#{asso_ref.klass.primary_key}"]
|
89
98
|
else
|
90
|
-
join_cond = "#{
|
91
|
-
join_cond = "#{
|
99
|
+
join_cond = "#{base_table_alias}.#{base_class.primary_key} = #{asso_table_alias}.#{asso_ref.foreign_key}"
|
100
|
+
join_cond = "#{asso_table_alias}.#{asso_ref.type} = '#{base_class.name}' and #{join_cond}" if asso_ref.type
|
92
101
|
@joins[asso_table] = [@join_count, asso_table, join_cond]
|
93
102
|
end
|
94
103
|
end
|
95
104
|
|
96
|
-
|
105
|
+
# This method parse a search parameter and its value
|
106
|
+
# then produce a ConditionGroup
|
107
|
+
def parse_search_parameters(attribute, value)
|
108
|
+
# handle _or_ parameters
|
97
109
|
attributes = attribute.split(@config[:or_separator])
|
98
110
|
if attributes.size > 1
|
99
111
|
cg = ConditionGroup.new
|
100
112
|
cg.set_relation(:or)
|
101
113
|
attributes.each do |a|
|
102
|
-
cg.add(
|
114
|
+
cg.add(parse_search_parameters(a, value))
|
103
115
|
end
|
104
116
|
return cg
|
105
117
|
end
|
106
118
|
|
119
|
+
# handle direct fields
|
107
120
|
unless attribute =~ /\./
|
108
|
-
condition =
|
121
|
+
condition = build_single_condition(@model_class, @model_class.table_name, attribute, value)
|
109
122
|
return condition
|
110
123
|
end
|
111
124
|
|
125
|
+
# handle association fields
|
112
126
|
association_fields = attribute.split(/\./)
|
113
127
|
field = association_fields.pop
|
114
128
|
|
115
129
|
base_class = @model_class
|
130
|
+
new_asso_chain = true
|
116
131
|
until association_fields.empty?
|
117
132
|
association_fields[0] = base_class.reflect_on_association(association_fields[0].to_sym)
|
118
|
-
insert_join(base_class, association_fields[0])
|
133
|
+
insert_join(base_class, association_fields[0], new_asso_chain)
|
134
|
+
new_asso_chain = false
|
119
135
|
base_class = association_fields.shift.klass
|
120
136
|
end
|
121
137
|
|
122
|
-
|
138
|
+
association_alias = table_name_to_alias(base_class.table_name)
|
139
|
+
build_single_condition(base_class, association_alias, field, value)
|
123
140
|
end
|
124
141
|
end
|
125
142
|
|
143
|
+
# This class holds a single condition
|
126
144
|
class ConditionItem
|
127
145
|
attr_reader :field, :verb, :value
|
128
146
|
|
@@ -133,6 +151,9 @@ module RailsSimpleSearch
|
|
133
151
|
end
|
134
152
|
end
|
135
153
|
|
154
|
+
# This class holds a ConditionGroup
|
155
|
+
# One ConditionGroup can hold one or more
|
156
|
+
# conditions
|
136
157
|
class ConditionGroup
|
137
158
|
def initialize(item = nil)
|
138
159
|
if item
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails-simple-search
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1
|
4
|
+
version: 1.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yi Zhang
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-12-
|
11
|
+
date: 2023-12-27 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: rails-simple-search is a light and easy to use gem. It could help developers
|
14
14
|
quickly build a search page.
|
@@ -32,7 +32,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
32
32
|
requirements:
|
33
33
|
- - ">="
|
34
34
|
- !ruby/object:Gem::Version
|
35
|
-
version:
|
35
|
+
version: 2.7.0
|
36
36
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - ">="
|