active_sort_order 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +10 -0
- data/LICENSE +21 -0
- data/README.md +140 -0
- data/Rakefile +21 -0
- data/lib/active_sort_order.rb +11 -0
- data/lib/active_sort_order/concerns/sort_order_concern.rb +67 -0
- data/lib/active_sort_order/version.rb +3 -0
- data/test/dummy_app/Rakefile +7 -0
- data/test/dummy_app/app/assets/config/manifest.js +3 -0
- data/test/dummy_app/app/assets/javascripts/application.js +0 -0
- data/test/dummy_app/app/assets/stylesheets/application.css +3 -0
- data/test/dummy_app/app/controllers/application_controller.rb +3 -0
- data/test/dummy_app/app/models/application_record.rb +3 -0
- data/test/dummy_app/app/models/post.rb +3 -0
- data/test/dummy_app/app/models/post_with_base_order_a.rb +7 -0
- data/test/dummy_app/app/models/post_with_base_order_a_and_b.rb +7 -0
- data/test/dummy_app/app/models/post_with_base_order_b.rb +7 -0
- data/test/dummy_app/app/models/post_with_base_order_b_and_a.rb +7 -0
- data/test/dummy_app/app/models/post_with_volatile_base_order.rb +7 -0
- data/test/dummy_app/app/models/test_helper.rb +0 -0
- data/test/dummy_app/app/views/layouts/application.html.erb +14 -0
- data/test/dummy_app/config.ru +4 -0
- data/test/dummy_app/config/application.rb +66 -0
- data/test/dummy_app/config/boot.rb +10 -0
- data/test/dummy_app/config/database.yml +11 -0
- data/test/dummy_app/config/environment.rb +5 -0
- data/test/dummy_app/config/environments/development.rb +30 -0
- data/test/dummy_app/config/environments/production.rb +60 -0
- data/test/dummy_app/config/environments/test.rb +41 -0
- data/test/dummy_app/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy_app/config/initializers/inflections.rb +10 -0
- data/test/dummy_app/config/initializers/mime_types.rb +5 -0
- data/test/dummy_app/config/initializers/secret_token.rb +11 -0
- data/test/dummy_app/config/initializers/session_store.rb +8 -0
- data/test/dummy_app/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy_app/config/locales/en.yml +5 -0
- data/test/dummy_app/config/routes.rb +6 -0
- data/test/dummy_app/config/secrets.yml +22 -0
- data/test/dummy_app/db/migrate/20210128155312_set_up_test_tables.rb +9 -0
- data/test/dummy_app/db/schema.rb +19 -0
- data/test/dummy_app/db/test.sqlite3 +0 -0
- data/test/dummy_app/log/test.log +10098 -0
- data/test/test_helper.rb +53 -0
- data/test/unit/active_sort_order_test.rb +116 -0
- data/test/unit/errors_test.rb +171 -0
- metadata +156 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 29d4251d6a9b034fe9354311a077024e119a7e5de8f15c566ce5e41671e8640a
|
4
|
+
data.tar.gz: 79e4e40796445bf88ee888289255989c8adbcfaecce2b44bb382363f38f29617
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c6cd7b26a6bbc32d2c0c9e78631dffc95c31fb9d907cb36ca37e70b9fdead4b56c4041dc57f2271ef1ee59a8cc5c381b8cea87f14d7f62504ce572663928d193
|
7
|
+
data.tar.gz: c13ca12d41b8afe6247120dac2cc1c02a636e55c55a5852ddffbda4ddb2198599c66d399f1f134246ecb52014d327cd0cfaa0f53161a51c397612736a6dd15ad
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
CHANGELOG
|
2
|
+
---------
|
3
|
+
|
4
|
+
- Unreleased
|
5
|
+
* [View Diff](https://github.com/westonganger/active_sort_order/compare/v0.9.0...master)
|
6
|
+
* Nothing yet
|
7
|
+
|
8
|
+
- v0.9.0 - Jan 29, 2021
|
9
|
+
* [View Diff](https://github.com/westonganger/active_sort_order/compare/371fc82...v0.9.0)
|
10
|
+
* Initial Release
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2021 Weston Ganger
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
# Active Sort Order
|
2
|
+
|
3
|
+
<a href="https://badge.fury.io/rb/active_sort_order" target="_blank"><img height="21" style='border:0px;height:21px;' border='0' src="https://badge.fury.io/rb/active_sort_order.svg" alt="Gem Version"></a>
|
4
|
+
<a href='https://travis-ci.com/westonganger/active_sort_order' target='_blank'><img height='21' style='border:0px;height:21px;' src='https://api.travis-ci.org/westonganger/active_sort_order.svg?branch=master' border='0' alt='Build Status' /></a>
|
5
|
+
<a href='https://rubygems.org/gems/active_sort_order' target='_blank'><img height='21' style='border:0px;height:21px;' src='https://ruby-gem-downloads-badge.herokuapp.com/active_sort_order?label=rubygems&type=total&total_label=downloads&color=brightgreen' border='0' alt='RubyGems Downloads' /></a>
|
6
|
+
|
7
|
+
Dead simple, fully customizable sorting pattern for ActiveRecord.
|
8
|
+
|
9
|
+
# Installation
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'active_sort_order'
|
13
|
+
```
|
14
|
+
|
15
|
+
Then add `include ActiveSortOrder` to your ApplicationRecord or models.
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
### Preferred
|
19
|
+
class ApplicationRecord < ActiveRecord::Base
|
20
|
+
include ActiveSortOrder
|
21
|
+
end
|
22
|
+
|
23
|
+
### OR for individual models
|
24
|
+
|
25
|
+
class Post < ActiveRecord::Base
|
26
|
+
include ActiveSortOrder
|
27
|
+
end
|
28
|
+
|
29
|
+
### OR for all models without an ApplicationRecord model
|
30
|
+
|
31
|
+
# config/initializers/active_sort_order.rb
|
32
|
+
ActiveSupport.on_load(:active_record) do
|
33
|
+
### Load for all ActiveRecord models
|
34
|
+
include ActiveSortOrder
|
35
|
+
end
|
36
|
+
```
|
37
|
+
|
38
|
+
# Usage
|
39
|
+
|
40
|
+
## Base Order
|
41
|
+
|
42
|
+
You will likely want to define a `base_sort_order` class method to each model.
|
43
|
+
|
44
|
+
This will be utilized when not providing a `:base_sort_order` argument.
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
def self.base_sort_order
|
48
|
+
"lower(#{table_name}.name) ASC, lower(#{table_name}.code) ASC" # for example
|
49
|
+
end
|
50
|
+
```
|
51
|
+
|
52
|
+
## Sorting
|
53
|
+
|
54
|
+
This gem defines one scope on your models: `sort_order`
|
55
|
+
|
56
|
+
This method uses `reorder` so any previously defined `order` will be removed.
|
57
|
+
|
58
|
+
In the below examples:
|
59
|
+
|
60
|
+
- `params[:sort]` is a String of the full SQL column name, feel free to use any SQL as required
|
61
|
+
- `params[:direction]` is a String, if nil/blank string value provided it will fallback to "ASC"
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
### Applies the classes base_sort_order (if defined)
|
65
|
+
Post.all.sort_order
|
66
|
+
|
67
|
+
### Use custom base_sort_order
|
68
|
+
Post.all.sort_order(base_sort_order: "lower(number) DESC")
|
69
|
+
|
70
|
+
### Output combined sort order (if present) AND applies the classes base_sort_order (if defined)
|
71
|
+
Post.all.sort_order(params[:sort], params[:direction])
|
72
|
+
|
73
|
+
### output combined sort order (if present) and applies a custom base_sort_order
|
74
|
+
post.all.sort_order(params[:sort], params[:direction], base_sort_order: "lower(number) desc, lower(code) asc")
|
75
|
+
|
76
|
+
### Skip the classes base_sort_order by providing false or nil
|
77
|
+
Post.all.sort_order(params[:sort], params[:direction], base_sort_order: false)
|
78
|
+
Post.all.sort_order(params[:sort], params[:direction], base_sort_order: nil)
|
79
|
+
```
|
80
|
+
|
81
|
+
## Additional Customizations
|
82
|
+
|
83
|
+
This gem is just ONE concern with ONE scope. I strongly encourage you to read the code for this library to understand how it works within your project so that you are capable of customizing the functionality later. You can always copy the code directly into your project for deeper project-specific customizations.
|
84
|
+
|
85
|
+
- [lib/active_sort_order/concerns/sort_order_concern.rb](./lib/active_sort_order/concerns/sort_order_concern.rb)
|
86
|
+
|
87
|
+
## Helper / View Examples
|
88
|
+
|
89
|
+
We do not provide built in helpers or view templates because this is a major restriction to applications. Instead we provide simple copy-and-pasteable starter templates
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
### app/helpers/application_helper.rb
|
93
|
+
|
94
|
+
module ApplicationHelper
|
95
|
+
|
96
|
+
def sort_link(column, title = nil, opts = {})
|
97
|
+
column = column.to_s
|
98
|
+
|
99
|
+
if title && title.is_a?(Hash)
|
100
|
+
opts = title
|
101
|
+
title = opts[:title]
|
102
|
+
end
|
103
|
+
|
104
|
+
title ||= column.titleize
|
105
|
+
|
106
|
+
if opts[:disabled]
|
107
|
+
return title
|
108
|
+
else
|
109
|
+
if params[:direction].present? && params[:sort].present?
|
110
|
+
direction = (column == params[:sort] && params[:direction] == "asc") ? "desc" : "asc"
|
111
|
+
else
|
112
|
+
direction = "asc"
|
113
|
+
end
|
114
|
+
|
115
|
+
return link_to(title, params.to_unsafe_h.merge(sort: column, direction: direction))
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
```
|
121
|
+
|
122
|
+
Then use the link helper within your views like:
|
123
|
+
|
124
|
+
```erb
|
125
|
+
<th>
|
126
|
+
<%= sort_link :name %>
|
127
|
+
</th>
|
128
|
+
|
129
|
+
<th>
|
130
|
+
<%= sort_link "companies.name", "Company Name" %>
|
131
|
+
</th>
|
132
|
+
|
133
|
+
<th>
|
134
|
+
<%= sort_link "companies.name", "Company Name", disabled: !@sort_enabled %>
|
135
|
+
</th>
|
136
|
+
```
|
137
|
+
|
138
|
+
# Credits
|
139
|
+
|
140
|
+
Created & Maintained by [Weston Ganger](https://westonganger.com) - [@westonganger](https://github.com/westonganger)
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/lib/active_sort_order/version.rb')
|
2
|
+
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
require "rake/testtask"
|
5
|
+
|
6
|
+
Rake::TestTask.new(:test) do |t|
|
7
|
+
t.libs << "test"
|
8
|
+
t.libs << "lib"
|
9
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
10
|
+
end
|
11
|
+
|
12
|
+
task default: [:test]
|
13
|
+
|
14
|
+
task :console do
|
15
|
+
require 'active_sort_order'
|
16
|
+
|
17
|
+
require 'test/dummy_app/app/models/post'
|
18
|
+
|
19
|
+
require 'irb'
|
20
|
+
binding.irb
|
21
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module ActiveSortOrder
|
2
|
+
module SortOrderConcern
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
|
7
|
+
scope :sort_order, ->(sort_str = nil, sort_direction = nil, base_sort_order: "NONE"){
|
8
|
+
if [String, Symbol, NilClass].none?{|x| sort_str.is_a?(x) }
|
9
|
+
raise ArgumentError.new("Invalid first argument `sort_str`, expecting a a String or Symbol")
|
10
|
+
end
|
11
|
+
|
12
|
+
if sort_str.present?
|
13
|
+
sort_str = sort_str.to_s
|
14
|
+
|
15
|
+
if sort_direction.is_a?(Symbol)
|
16
|
+
sort_direction = sort_direction.to_s.gsub('_', ' ')
|
17
|
+
end
|
18
|
+
|
19
|
+
if sort_direction.nil? || (sort_direction.is_a?(String) && sort_direction == "")
|
20
|
+
sort_direction = "ASC"
|
21
|
+
elsif !sort_direction.is_a?(String)
|
22
|
+
raise ArgumentError.new("Invalid second argument `sort_direction` #{sort_direction}, expecting a a String or Symbol")
|
23
|
+
else
|
24
|
+
valid_directions = [
|
25
|
+
"ASC",
|
26
|
+
"DESC",
|
27
|
+
"ASC NULLS FIRST",
|
28
|
+
"ASC NULLS LAST",
|
29
|
+
"DESC NULLS FIRST",
|
30
|
+
"DESC NULLS LAST",
|
31
|
+
].freeze
|
32
|
+
|
33
|
+
sanitized_sort_direction = sort_direction.split(' ').join(' ')
|
34
|
+
|
35
|
+
if !valid_directions.include?(sanitized_sort_direction.upcase)
|
36
|
+
raise ArgumentError.new("Invalid second argument `sort_direction` #{sort_direction}")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
sql_str = "#{sort_str} #{sanitized_sort_direction}"
|
41
|
+
end
|
42
|
+
|
43
|
+
if base_sort_order == "NONE" && self.klass.respond_to?(:base_sort_order)
|
44
|
+
base_sort_order = self.klass.base_sort_order
|
45
|
+
end
|
46
|
+
|
47
|
+
if base_sort_order && !base_sort_order.is_a?(String)
|
48
|
+
raise ArgumentError.new("Invalid :base_sort_order #{base_sort_order}, expecting a String")
|
49
|
+
end
|
50
|
+
|
51
|
+
if base_sort_order.present?
|
52
|
+
if sql_str.present?
|
53
|
+
sql_str << ", #{base_sort_order}"
|
54
|
+
else
|
55
|
+
sql_str = base_sort_order
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
sanitized_str = sql_str.blank? ? nil : Arel.sql(sanitize_sql_for_order(sql_str))
|
60
|
+
|
61
|
+
next self.reorder(sanitized_str)
|
62
|
+
}
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
3
|
+
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
4
|
+
|
5
|
+
require File.expand_path('../config/application', __FILE__)
|
6
|
+
|
7
|
+
Dummy::Application.load_tasks
|
File without changes
|
File without changes
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require File.expand_path('../boot', __FILE__)
|
2
|
+
|
3
|
+
require 'warning'
|
4
|
+
Warning.ignore(
|
5
|
+
%r{mail/parsers/address_lists_parser}, ### Hide mail gem warnings
|
6
|
+
)
|
7
|
+
|
8
|
+
require 'rails/all'
|
9
|
+
|
10
|
+
Bundler.require
|
11
|
+
|
12
|
+
module Dummy
|
13
|
+
class Application < Rails::Application
|
14
|
+
# Settings in config/environments/* take precedence over those specified here.
|
15
|
+
# Application configuration should go into files in config/initializers
|
16
|
+
# -- all .rb files in that directory are automatically loaded.
|
17
|
+
|
18
|
+
# Custom directories with classes and modules you want to be autoloadable.
|
19
|
+
# config.autoload_paths += %W(#{config.root}/extras)
|
20
|
+
|
21
|
+
# Only load the plugins named here, in the order given (default is alphabetical).
|
22
|
+
# :all can be used as a placeholder for all plugins not explicitly named.
|
23
|
+
# config.plugins = [ :exception_notification, :ssl_requirement, :all ]
|
24
|
+
|
25
|
+
# Activate observers that should always be running.
|
26
|
+
# config.active_record.observers = :cacher, :garbage_collector, :forum_observer
|
27
|
+
|
28
|
+
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
|
29
|
+
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
|
30
|
+
# config.time_zone = 'Central Time (US & Canada)'
|
31
|
+
|
32
|
+
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
|
33
|
+
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
|
34
|
+
# config.i18n.default_locale = :de
|
35
|
+
|
36
|
+
# Configure the default encoding used in templates for Ruby 1.9.
|
37
|
+
config.encoding = "utf-8"
|
38
|
+
|
39
|
+
# Configure sensitive parameters which will be filtered from the log file.
|
40
|
+
config.filter_parameters += [:password]
|
41
|
+
|
42
|
+
# Enable the asset pipeline
|
43
|
+
config.assets.enabled = true
|
44
|
+
|
45
|
+
config.assets.quiet = true
|
46
|
+
|
47
|
+
# Version of your assets, change this if you want to expire all your assets
|
48
|
+
config.assets.version = '1.0'
|
49
|
+
|
50
|
+
config.generators.test_framework = false
|
51
|
+
config.generators.helper = false
|
52
|
+
config.generators.stylesheets = false
|
53
|
+
config.generators.javascripts = false
|
54
|
+
|
55
|
+
config.after_initialize do
|
56
|
+
ActiveRecord::Migration.migrate(Rails.root.join("db/migrate/*").to_s)
|
57
|
+
end
|
58
|
+
|
59
|
+
if ActiveRecord.respond_to?(:gem_version)
|
60
|
+
gem_version = ActiveRecord.gem_version
|
61
|
+
if gem_version.to_s.start_with?("5.2.")
|
62
|
+
config.active_record.sqlite3.represent_boolean_as_integer = true
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|