rails-simple-search 1.1.10 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Gem Version](https://badge.fury.io/rb/rails-simple-search.svg)](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
|
- - ">="
|