├── .github └── workflows │ └── codeql-analysis.yml ├── .gitignore ├── .rubocop.yml ├── .ruby-version ├── Gemfile ├── Gemfile.lock ├── Procfile ├── README.md ├── Rakefile ├── app.json ├── app ├── assets │ ├── config │ │ └── manifest.js │ ├── images │ │ └── rails.png │ ├── javascripts │ │ ├── application.js │ │ └── search.js │ └── stylesheets │ │ ├── application.css │ │ └── users.scss ├── controllers │ ├── application_controller.rb │ └── users_controller.rb ├── helpers │ ├── application_helper.rb │ └── users_helper.rb ├── mailers │ └── .gitkeep ├── models │ ├── .gitkeep │ ├── application_record.rb │ ├── comment.rb │ ├── post.rb │ ├── posts_mixin.rb │ ├── role.rb │ ├── tag.rb │ ├── tagging.rb │ └── user.rb └── views │ ├── layouts │ └── application.html.erb │ └── users │ ├── _attribute_fields.erb │ ├── _condition_fields.erb │ ├── _grouping_fields.erb │ ├── _results.erb │ ├── _sort_fields.erb │ ├── _value_fields.erb │ ├── advanced_search.erb │ └── index.erb ├── bin ├── bundle ├── rails ├── rake ├── setup └── update ├── config.ru ├── config ├── application.rb ├── boot.rb ├── credentials.yml ├── database.yml ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ └── test.rb ├── initializers │ ├── application_controller_renderer.rb │ ├── assets.rb │ ├── backtrace_silencers.rb │ ├── content_security_policy.rb │ ├── cookies_serializer.rb │ ├── filter_parameter_logging.rb │ ├── inflections.rb │ ├── mime_types.rb │ ├── new_framework_defaults_7_1.rb │ ├── permissions_policy.rb │ ├── secret_token.rb │ ├── session_store.rb │ └── wrap_parameters.rb ├── locales │ └── en.yml ├── puma.rb ├── routes.rb └── spring.rb ├── db ├── migrate │ ├── 20110609001909_create_users.rb │ ├── 20110609002030_create_posts.rb │ ├── 20110609002121_create_comments.rb │ ├── 20110609002140_create_roles.rb │ ├── 20110609002232_create_tags.rb │ └── 20110609002321_create_taggings.rb ├── schema.rb └── seeds.rb ├── doc └── README_FOR_APP ├── lib └── tasks │ └── .gitkeep ├── log └── .gitkeep ├── public ├── 404.html ├── 422.html ├── 500.html ├── favicon.ico └── robots.txt ├── script └── rails ├── test ├── fixtures │ ├── .gitkeep │ ├── comments.yml │ ├── posts.yml │ ├── roles.yml │ ├── taggings.yml │ ├── tags.yml │ └── users.yml ├── functional │ ├── .gitkeep │ └── users_controller_test.rb ├── integration │ └── .gitkeep ├── test_helper.rb └── unit │ ├── .gitkeep │ ├── comment_test.rb │ ├── helpers │ └── users_helper_test.rb │ ├── post_test.rb │ ├── role_test.rb │ ├── tag_test.rb │ ├── tagging_test.rb │ └── user_test.rb └── vendor ├── assets └── stylesheets │ └── .gitkeep └── plugins └── .gitkeep /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ main ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ main ] 20 | schedule: 21 | - cron: '35 2 * * 3' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'javascript', 'ruby' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://git.io/codeql-language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v3 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v2 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 52 | 53 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 54 | # If this step fails, then you should remove it and run the build manually (see below) 55 | - name: Autobuild 56 | uses: github/codeql-action/autobuild@v2 57 | 58 | # ℹ️ Command-line programs to run using the OS shell. 59 | # 📚 https://git.io/JvXDl 60 | 61 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 62 | # and modify them (or add more) to build your code if your project 63 | # uses a compiled language 64 | 65 | #- run: | 66 | # make bootstrap 67 | # make release 68 | 69 | - name: Perform CodeQL Analysis 70 | uses: github/codeql-action/analyze@v2 71 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .bundle 2 | db/*.sqlite3 3 | log/*.log 4 | tmp/ 5 | .sass-cache/ 6 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | AllCops: 4 | DisabledByDefault: true 5 | TargetRubyVersion: 3.1 6 | 7 | Style/StringLiterals: 8 | EnforcedStyle: double_quotes 9 | Enabled: true 10 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 3.4.4 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | ruby file: ".ruby-version" 4 | 5 | gem "rails", "~> 7.1.0" 6 | 7 | # Use PostgreSQL as the database for Active Record 8 | gem "pg", "~> 1.0" 9 | # Use Puma as the app server 10 | gem "puma", "~> 5.6" 11 | # Use SCSS for stylesheets 12 | gem "sass-rails", "~> 5.0" 13 | # Use Uglifier as compressor for JavaScript assets 14 | gem "uglifier", ">= 1.3.0" 15 | # Use jquery as the JavaScript library 16 | gem "jquery-rails" 17 | # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks 18 | # gem 'turbolinks', '~> 5' 19 | # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder 20 | # gem 'jbuilder', '~> 2.5' 21 | # Use ActiveModel has_secure_password 22 | # gem 'bcrypt', '~> 3.1.7' 23 | gem "ransack" 24 | gem "factory_bot" 25 | gem "faker" 26 | 27 | group :development, :test do 28 | # Call 'byebug' anywhere in the code to stop execution and get a debugger console 29 | gem "byebug", platform: :mri 30 | end 31 | 32 | group :development do 33 | # Access an IRB console on exception pages or by using <%= console %> anywhere in the code. 34 | gem "web-console" 35 | gem "listen", "~> 3.0.5" 36 | 37 | gem "rubocop", "~> 1.29" 38 | end 39 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | actioncable (7.1.5.1) 5 | actionpack (= 7.1.5.1) 6 | activesupport (= 7.1.5.1) 7 | nio4r (~> 2.0) 8 | websocket-driver (>= 0.6.1) 9 | zeitwerk (~> 2.6) 10 | actionmailbox (7.1.5.1) 11 | actionpack (= 7.1.5.1) 12 | activejob (= 7.1.5.1) 13 | activerecord (= 7.1.5.1) 14 | activestorage (= 7.1.5.1) 15 | activesupport (= 7.1.5.1) 16 | mail (>= 2.7.1) 17 | net-imap 18 | net-pop 19 | net-smtp 20 | actionmailer (7.1.5.1) 21 | actionpack (= 7.1.5.1) 22 | actionview (= 7.1.5.1) 23 | activejob (= 7.1.5.1) 24 | activesupport (= 7.1.5.1) 25 | mail (~> 2.5, >= 2.5.4) 26 | net-imap 27 | net-pop 28 | net-smtp 29 | rails-dom-testing (~> 2.2) 30 | actionpack (7.1.5.1) 31 | actionview (= 7.1.5.1) 32 | activesupport (= 7.1.5.1) 33 | nokogiri (>= 1.8.5) 34 | racc 35 | rack (>= 2.2.4) 36 | rack-session (>= 1.0.1) 37 | rack-test (>= 0.6.3) 38 | rails-dom-testing (~> 2.2) 39 | rails-html-sanitizer (~> 1.6) 40 | actiontext (7.1.5.1) 41 | actionpack (= 7.1.5.1) 42 | activerecord (= 7.1.5.1) 43 | activestorage (= 7.1.5.1) 44 | activesupport (= 7.1.5.1) 45 | globalid (>= 0.6.0) 46 | nokogiri (>= 1.8.5) 47 | actionview (7.1.5.1) 48 | activesupport (= 7.1.5.1) 49 | builder (~> 3.1) 50 | erubi (~> 1.11) 51 | rails-dom-testing (~> 2.2) 52 | rails-html-sanitizer (~> 1.6) 53 | activejob (7.1.5.1) 54 | activesupport (= 7.1.5.1) 55 | globalid (>= 0.3.6) 56 | activemodel (7.1.5.1) 57 | activesupport (= 7.1.5.1) 58 | activerecord (7.1.5.1) 59 | activemodel (= 7.1.5.1) 60 | activesupport (= 7.1.5.1) 61 | timeout (>= 0.4.0) 62 | activestorage (7.1.5.1) 63 | actionpack (= 7.1.5.1) 64 | activejob (= 7.1.5.1) 65 | activerecord (= 7.1.5.1) 66 | activesupport (= 7.1.5.1) 67 | marcel (~> 1.0) 68 | activesupport (7.1.5.1) 69 | base64 70 | benchmark (>= 0.3) 71 | bigdecimal 72 | concurrent-ruby (~> 1.0, >= 1.0.2) 73 | connection_pool (>= 2.2.5) 74 | drb 75 | i18n (>= 1.6, < 2) 76 | logger (>= 1.4.2) 77 | minitest (>= 5.1) 78 | mutex_m 79 | securerandom (>= 0.3) 80 | tzinfo (~> 2.0) 81 | ast (2.4.3) 82 | base64 (0.2.0) 83 | benchmark (0.4.0) 84 | bigdecimal (3.1.9) 85 | bindex (0.8.1) 86 | builder (3.2.4) 87 | byebug (11.1.3) 88 | concurrent-ruby (1.3.5) 89 | connection_pool (2.5.3) 90 | crass (1.0.6) 91 | date (3.4.1) 92 | drb (2.2.1) 93 | erb (5.0.1) 94 | erubi (1.12.0) 95 | execjs (2.8.1) 96 | factory_bot (6.5.1) 97 | activesupport (>= 6.1.0) 98 | faker (2.20.0) 99 | i18n (>= 1.8.11, < 2) 100 | ffi (1.15.5) 101 | globalid (1.1.0) 102 | activesupport (>= 5.0) 103 | i18n (1.14.7) 104 | concurrent-ruby (~> 1.0) 105 | io-console (0.8.0) 106 | irb (1.15.2) 107 | pp (>= 0.6.0) 108 | rdoc (>= 4.0.0) 109 | reline (>= 0.4.2) 110 | jquery-rails (4.4.0) 111 | rails-dom-testing (>= 1, < 3) 112 | railties (>= 4.2.0) 113 | thor (>= 0.14, < 2.0) 114 | json (2.12.0) 115 | language_server-protocol (3.17.0.5) 116 | lint_roller (1.1.0) 117 | listen (3.0.8) 118 | rb-fsevent (~> 0.9, >= 0.9.4) 119 | rb-inotify (~> 0.9, >= 0.9.7) 120 | logger (1.7.0) 121 | loofah (2.24.1) 122 | crass (~> 1.0.2) 123 | nokogiri (>= 1.12.0) 124 | mail (2.8.0.1) 125 | mini_mime (>= 0.1.1) 126 | net-imap 127 | net-pop 128 | net-smtp 129 | marcel (1.0.2) 130 | mini_mime (1.1.2) 131 | mini_portile2 (2.8.9) 132 | minitest (5.25.5) 133 | mutex_m (0.3.0) 134 | net-imap (0.3.9) 135 | date 136 | net-protocol 137 | net-pop (0.1.2) 138 | net-protocol 139 | net-protocol (0.2.2) 140 | timeout 141 | net-smtp (0.3.3) 142 | net-protocol 143 | nio4r (2.7.4) 144 | nokogiri (1.18.8) 145 | mini_portile2 (~> 2.8.2) 146 | racc (~> 1.4) 147 | parallel (1.27.0) 148 | parser (3.3.8.0) 149 | ast (~> 2.4.1) 150 | racc 151 | pg (1.3.3) 152 | pp (0.6.2) 153 | prettyprint 154 | prettyprint (0.2.0) 155 | prism (1.4.0) 156 | psych (5.2.6) 157 | date 158 | stringio 159 | puma (5.6.9) 160 | nio4r (~> 2.0) 161 | racc (1.8.1) 162 | rack (2.2.14) 163 | rack-session (1.0.2) 164 | rack (< 3) 165 | rack-test (2.1.0) 166 | rack (>= 1.3) 167 | rackup (1.0.1) 168 | rack (< 3) 169 | webrick 170 | rails (7.1.5.1) 171 | actioncable (= 7.1.5.1) 172 | actionmailbox (= 7.1.5.1) 173 | actionmailer (= 7.1.5.1) 174 | actionpack (= 7.1.5.1) 175 | actiontext (= 7.1.5.1) 176 | actionview (= 7.1.5.1) 177 | activejob (= 7.1.5.1) 178 | activemodel (= 7.1.5.1) 179 | activerecord (= 7.1.5.1) 180 | activestorage (= 7.1.5.1) 181 | activesupport (= 7.1.5.1) 182 | bundler (>= 1.15.0) 183 | railties (= 7.1.5.1) 184 | rails-dom-testing (2.2.0) 185 | activesupport (>= 5.0.0) 186 | minitest 187 | nokogiri (>= 1.6) 188 | rails-html-sanitizer (1.6.1) 189 | loofah (~> 2.21) 190 | nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) 191 | railties (7.1.5.1) 192 | actionpack (= 7.1.5.1) 193 | activesupport (= 7.1.5.1) 194 | irb 195 | rackup (>= 1.0.0) 196 | rake (>= 12.2) 197 | thor (~> 1.0, >= 1.2.2) 198 | zeitwerk (~> 2.6) 199 | rainbow (3.1.1) 200 | rake (13.2.1) 201 | ransack (4.3.0) 202 | activerecord (>= 6.1.5) 203 | activesupport (>= 6.1.5) 204 | i18n 205 | rb-fsevent (0.11.1) 206 | rb-inotify (0.10.1) 207 | ffi (~> 1.0) 208 | rdoc (6.14.0) 209 | erb 210 | psych (>= 4.0.0) 211 | regexp_parser (2.10.0) 212 | reline (0.6.1) 213 | io-console (~> 0.5) 214 | rubocop (1.75.6) 215 | json (~> 2.3) 216 | language_server-protocol (~> 3.17.0.2) 217 | lint_roller (~> 1.1.0) 218 | parallel (~> 1.10) 219 | parser (>= 3.3.0.2) 220 | rainbow (>= 2.2.2, < 4.0) 221 | regexp_parser (>= 2.9.3, < 3.0) 222 | rubocop-ast (>= 1.44.0, < 2.0) 223 | ruby-progressbar (~> 1.7) 224 | unicode-display_width (>= 2.4.0, < 4.0) 225 | rubocop-ast (1.44.1) 226 | parser (>= 3.3.7.2) 227 | prism (~> 1.4) 228 | ruby-progressbar (1.13.0) 229 | sass (3.7.4) 230 | sass-listen (~> 4.0.0) 231 | sass-listen (4.0.0) 232 | rb-fsevent (~> 0.9, >= 0.9.4) 233 | rb-inotify (~> 0.9, >= 0.9.7) 234 | sass-rails (5.1.0) 235 | railties (>= 5.2.0) 236 | sass (~> 3.1) 237 | sprockets (>= 2.8, < 4.0) 238 | sprockets-rails (>= 2.0, < 4.0) 239 | tilt (>= 1.1, < 3) 240 | securerandom (0.4.1) 241 | sprockets (3.7.2) 242 | concurrent-ruby (~> 1.0) 243 | rack (> 1, < 3) 244 | sprockets-rails (3.4.2) 245 | actionpack (>= 5.2) 246 | activesupport (>= 5.2) 247 | sprockets (>= 3.0.0) 248 | stringio (3.1.7) 249 | thor (1.3.0) 250 | tilt (2.0.10) 251 | timeout (0.4.3) 252 | tzinfo (2.0.6) 253 | concurrent-ruby (~> 1.0) 254 | uglifier (4.2.0) 255 | execjs (>= 0.3.0, < 3) 256 | unicode-display_width (3.1.4) 257 | unicode-emoji (~> 4.0, >= 4.0.4) 258 | unicode-emoji (4.0.4) 259 | web-console (4.2.0) 260 | actionview (>= 6.0.0) 261 | activemodel (>= 6.0.0) 262 | bindex (>= 0.4.0) 263 | railties (>= 6.0.0) 264 | webrick (1.9.1) 265 | websocket-driver (0.7.5) 266 | websocket-extensions (>= 0.1.0) 267 | websocket-extensions (0.1.5) 268 | zeitwerk (2.6.12) 269 | 270 | PLATFORMS 271 | ruby 272 | 273 | DEPENDENCIES 274 | byebug 275 | factory_bot 276 | faker 277 | jquery-rails 278 | listen (~> 3.0.5) 279 | pg (~> 1.0) 280 | puma (~> 5.6) 281 | rails (~> 7.1.0) 282 | ransack 283 | rubocop (~> 1.29) 284 | sass-rails (~> 5.0) 285 | uglifier (>= 1.3.0) 286 | web-console 287 | 288 | RUBY VERSION 289 | ruby 3.4.4p34 290 | 291 | BUNDLED WITH 292 | 2.6.9 293 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | release: DISABLE_DATABASE_ENVIRONMENT_CHECK=1 rails db:migrate db:seed 2 | web: bundle exec puma -t 5:5 -p ${PORT:-3000} -e ${RACK_ENV:-development} 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ransack Demo Application 2 | 3 | This is a quick demonstration of how you might use 4 | [Ransack](https://github.com/activerecord-hackery/ransack) in a Rails 7 5 | application to create an "advanced" search form, with nesting, etc. 6 | 7 | The main things you'll want to note are: 8 | 9 | * app/models/user.rb - Demonstration of: 10 | - using a "ransacker" (a virtual, searchable "column") to allow searching on 11 | full names from concatenated first and last names. 12 | - whitelisting attributes allowed for searching using `ransackable_attributes`. 13 | - whitelisting attributes allowed for sorting using `ransortable_attributes`. 14 | * app/views/users/ - Search form and various partials used in dynamic form. 15 | * app/helpers/application_helper.rb - `setup_search_form`, which creates a 16 | Javascript search object with a grouping template, since we can't dynamically 17 | create grouping templates in Ruby (groupings can contain other groupings, 18 | would end up in infinite recursion). The rest of the methods in here are 19 | pretty much the same as the nested field helpers in Ryan Bates' 20 | [Railscast #197](http://railscasts.com/episodes/197-nested-model-form-part-2). 21 | * app/assets/javascripts/search.js - JS to handle addition/removal of fields, as 22 | well as nesting fields (adding a grouping from the previously mentioned 23 | grouping template) 24 | 25 | Let us know if you have any questions, and happy ransacking! 26 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require_relative "config/application" 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ransack_demo", 3 | "description": "A demo app using Ransack to create advanced search forms", 4 | "env": { 5 | "LANG": { 6 | "required": true, 7 | "value": "en_US.UTF-8" 8 | }, 9 | "RACK_ENV": { 10 | "required": true, 11 | "value": "production" 12 | }, 13 | "RAILS_ENV": { 14 | "required": true, 15 | "value": "production" 16 | } 17 | }, 18 | "environments": { 19 | "review": { 20 | "env": { 21 | "LANG": { 22 | "required": true, 23 | "value": "en_US.UTF-8" 24 | }, 25 | "RACK_ENV": { 26 | "required": true, 27 | "value": "production" 28 | }, 29 | "RAILS_ENV": { 30 | "required": true, 31 | "value": "production" 32 | } 33 | } 34 | } 35 | }, 36 | "formation": { 37 | "web": { 38 | "quantity": 1 39 | } 40 | }, 41 | "addons": [ 42 | "heroku-postgresql" 43 | ], 44 | "buildpacks": [ 45 | { 46 | "url": "heroku/ruby" 47 | } 48 | ], 49 | "stack": "heroku-22" 50 | } 51 | -------------------------------------------------------------------------------- /app/assets/config/manifest.js: -------------------------------------------------------------------------------- 1 | //= link_tree ../images 2 | //= link_directory ../javascripts .js 3 | //= link_directory ../stylesheets .css 4 | -------------------------------------------------------------------------------- /app/assets/images/rails.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/activerecord-hackery/ransack_demo/e8d87eb29289256989e474a8c4c609466a63a893/app/assets/images/rails.png -------------------------------------------------------------------------------- /app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will 2 | // include all the files listed below. Any JavaScript/Coffee file within this 3 | // directory, lib/assets/javascripts, vendor/assets/javascripts, or any 4 | // plugin's vendor/assets/javascripts directory can be referenced here using a 5 | // relative path. It's not advisable to add code directly here, but if you do, 6 | // it'll appear at the bottom of the compiled file. JavaScript code in this 7 | // file should be added after the last require_* statement. Read Sprockets 8 | // README (https://github.com/rails/sprockets#sprockets-directives) for details 9 | // about supported directives. 10 | // 11 | //= require jquery2 12 | //= require jquery_ujs 13 | //= require search 14 | // require_tree . 15 | -------------------------------------------------------------------------------- /app/assets/javascripts/search.js: -------------------------------------------------------------------------------- 1 | this.Search = (function() { 2 | function Search(templates) { 3 | this.templates = templates != null ? templates : {}; 4 | } 5 | 6 | Search.prototype.remove_fields = function(button) { 7 | return $(button).closest('.fields').remove(); 8 | }; 9 | 10 | Search.prototype.add_fields = function(button, type, content) { 11 | var new_id, regexp; 12 | new_id = new Date().getTime(); 13 | regexp = new RegExp('new_' + type, 'g'); 14 | return $(button).before(content.replace(regexp, new_id)); 15 | }; 16 | 17 | Search.prototype.nest_fields = function(button, type) { 18 | var id_regexp, new_id, object_name, sanitized_object_name, template; 19 | new_id = new Date().getTime(); 20 | id_regexp = new RegExp('new_' + type, 'g'); 21 | template = this.templates[type]; 22 | object_name = $(button).closest('.fields').attr('data-object-name'); 23 | sanitized_object_name = object_name.replace(/\]\[|[^-a-zA-Z0-9:.]/g, '_').replace(/_$/, ''); 24 | template = template.replace(/new_object_name\[/g, object_name + "["); 25 | template = template.replace(/new_object_name_/, sanitized_object_name + '_'); 26 | return $(button).before(template.replace(id_regexp, new_id)); 27 | }; 28 | 29 | return Search; 30 | 31 | })(); 32 | -------------------------------------------------------------------------------- /app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will 3 | * include all the files listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, 6 | * vendor/assets/stylesheets, or any plugin's vendor/assets/stylesheets 7 | * directory can be referenced here using a relative path. 8 | * 9 | * You're free to add application-wide styles to this file and they'll appear 10 | * at the bottom of the compiled file so the styles you add here take 11 | * precedence over styles defined in any other CSS/SCSS files in this 12 | * directory. Styles in this file should be added after the last require_* 13 | * statement. It is generally better to create a new file per style scope. 14 | * 15 | * require_self 16 | * require_tree . 17 | *= require users 18 | */ 19 | -------------------------------------------------------------------------------- /app/assets/stylesheets/users.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the Users controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: https://sass-lang.com/ 4 | header { 5 | font-size: 1em; 6 | margin-bottom: 1.25em; 7 | } 8 | 9 | body { 10 | font-family: "Helvetica", "Arial", sans-serif; 11 | margin: 0 auto; 12 | max-width: 76em; 13 | line-height: 1.5; 14 | padding: 1em 1em; 15 | color: #555; 16 | } 17 | 18 | h1 { 19 | margin: 0 0 0.5em; 20 | } 21 | 22 | h1, h2, strong, code { 23 | color: #333; 24 | } 25 | 26 | h2 { 27 | font-size: 1.25em; 28 | margin-top: 0.75em; 29 | padding-top: 1em; 30 | } 31 | 32 | section { 33 | margin-top: 0.75em; 34 | } 35 | 36 | a { 37 | color: rgba(150, 150, 200, 1); 38 | } 39 | 40 | fieldset { 41 | font-size: 1em; 42 | margin-top: 0.75em; 43 | border: none; 44 | border-radius: 5px; 45 | background-color: rgba(150, 150, 200, 0.3); 46 | overflow: hidden; 47 | } 48 | 49 | legend { 50 | margin-left:-12px; 51 | margin-right:-12px; 52 | padding: 12px; 53 | background-color: rgba(150, 150, 200, 1); 54 | color: white; 55 | border-radius: 0px; 56 | width: 100%; 57 | } 58 | 59 | code { 60 | background: #f5f7f9; 61 | padding: 8px; 62 | line-height: 2.25; 63 | border: 1.5px solid #d8dee9; 64 | border-radius: 4px; 65 | vertical-align: text-bottom; 66 | } 67 | 68 | table { 69 | border-horizontal-spacing: 0px; 70 | -webkit-border-horizontal-spacing: 0px; 71 | -webkit-border-vertical-spacing: 0px; 72 | } 73 | 74 | tbody tr:nth-child(odd) { 75 | background-color: #ececec; 76 | } 77 | 78 | tr { 79 | line-height: 2.5 80 | } 81 | 82 | th, td { 83 | padding: 0 8px; 84 | text-align: left; 85 | } 86 | 87 | footer { 88 | font-size: 1em; 89 | margin-top: 2em; 90 | } 91 | 92 | .add_fields { 93 | margin-top: 1em; 94 | } 95 | 96 | .btn { 97 | line-height: 2; 98 | } 99 | 100 | .btn { 101 | background-color: #fff; 102 | color: #aaa; 103 | border: none; 104 | border-radius: 20px; 105 | cursor: pointer; 106 | padding: 6px; 107 | padding-left: 12px; 108 | padding-right: 12px; 109 | } 110 | 111 | .btn--invert { 112 | background-color: #aaa; 113 | color: #fff; 114 | } 115 | 116 | .btn:hover { 117 | background-color: #333; 118 | color: white; 119 | } 120 | 121 | .btn--invert:hover { 122 | background-color: #bbb; 123 | } 124 | 125 | .cbx { 126 | margin: 1em; 127 | } 128 | 129 | -------------------------------------------------------------------------------- /app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | protect_from_forgery 3 | end 4 | -------------------------------------------------------------------------------- /app/controllers/users_controller.rb: -------------------------------------------------------------------------------- 1 | class UsersController < ApplicationController 2 | include UsersHelper 3 | 4 | def index 5 | @search = ransack_params 6 | @users = ransack_result 7 | end 8 | 9 | def advanced_search 10 | @search = ransack_params 11 | @search.build_grouping unless @search.groupings.any? 12 | @users = ransack_result 13 | end 14 | 15 | private 16 | def ransack_params 17 | User.includes(:posts).ransack(params[:q]) 18 | end 19 | 20 | def ransack_result 21 | @search.result(distinct: user_wants_distinct_results?) 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module ApplicationHelper 3 | def setup_search_form(builder) 4 | fields = builder.grouping_fields builder.object.new_grouping, 5 | object_name: "new_object_name", child_index: "new_grouping" do |f| 6 | render("grouping_fields", f: f) 7 | end 8 | content_for :document_ready, %Q{ 9 | var search = new Search({grouping: "#{escape_javascript(fields)}"}); 10 | $(document).on("click", "button.add_fields", function() { 11 | search.add_fields(this, $(this).data('fieldType'), $(this).data('content')); 12 | return false; 13 | }); 14 | $(document).on("click", "button.remove_fields", function() { 15 | search.remove_fields(this); 16 | return false; 17 | }); 18 | $(document).on("click", "button.nest_fields", function() { 19 | search.nest_fields(this, $(this).data('fieldType')); 20 | return false; 21 | }); 22 | }.html_safe 23 | end 24 | 25 | def button_to_remove_fields 26 | tag.button "Remove", class: "remove_fields btn" 27 | end 28 | 29 | def button_to_add_fields(f, type) 30 | new_object, name = f.object.send("build_#{type}"), "#{type}_fields" 31 | fields = f.send(name, new_object, child_index: "new_#{type}") do |builder| 32 | render(name, f: builder) 33 | end 34 | 35 | tag.button button_label[type], class: "add_fields btn", 'data-field-type': type, 36 | 'data-content': "#{fields}" 37 | end 38 | 39 | def button_to_nest_fields(type) 40 | tag.button button_label[type], class: "nest_fields btn", 'data-field-type': type 41 | end 42 | 43 | def button_label 44 | { value: "Add Value", 45 | condition: "Add Condition", 46 | sort: "Add Sort", 47 | grouping: "Add Condition Group" }.freeze 48 | end 49 | 50 | def app_info 51 | @@app_info ||= "#{ 52 | tag.strong 'Ransack demo app' 53 | } running on Ruby #{RUBY_VERSION}, Rails #{Rails::VERSION::STRING 54 | } and #{User.postgres_version} - #{source_code_link}".html_safe 55 | end 56 | 57 | def source_code_link 58 | link_to "Source code for this demo available on GitHub", 59 | "https://github.com/activerecord-hackery/ransack_demo" 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /app/helpers/users_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module UsersHelper 3 | def action 4 | if action_name == "advanced_search" 5 | :post 6 | else 7 | :get 8 | end 9 | end 10 | 11 | def link_to_toggle_search_modes 12 | if action_name == "advanced_search" 13 | link_to("Go to Simple mode", users_path) 14 | else 15 | link_to("Go to Advanced mode", advanced_search_users_path) 16 | end 17 | end 18 | 19 | def user_column_headers 20 | %i(id first_name last_name email created_at updated_at).freeze 21 | end 22 | 23 | def user_column_fields 24 | %i(id first_name last_name email created updated).freeze 25 | end 26 | 27 | def results_limit 28 | # max number of search results to display 29 | 10 30 | end 31 | 32 | def post_title_length 33 | # max number of characters in posts titles to display 34 | 14 35 | end 36 | 37 | def post_title_header_labels 38 | %w(1 2 3).freeze 39 | end 40 | 41 | def user_posts_and_comments 42 | %w(posts other_posts comments).freeze 43 | end 44 | 45 | def condition_fields 46 | %w(fields condition).freeze 47 | end 48 | 49 | def value_fields 50 | %w(fields value).freeze 51 | end 52 | 53 | def display_distinct_label_and_check_box 54 | tag.section do 55 | check_box_tag(:distinct, "1", user_wants_distinct_results?, class: :cbx) + 56 | label_tag(:distinct, "Return distinct records") 57 | end 58 | end 59 | 60 | def user_wants_distinct_results? 61 | params[:distinct].to_i == 1 62 | end 63 | 64 | def display_query_sql(users) 65 | tag.p("SQL:") + tag.code(users.to_sql) 66 | end 67 | 68 | def display_results_header(count) 69 | if count > results_limit 70 | "Your first #{results_limit} results out of #{count} total" 71 | else 72 | "Your #{pluralize(count, 'result')}" 73 | end 74 | end 75 | 76 | def display_sort_column_headers(search) 77 | user_column_headers.reduce(String.new) do |string, field| 78 | string << (tag.th sort_link(search, field, method: action)) 79 | end + 80 | post_title_header_labels.reduce(String.new) do |str, i| 81 | str << (tag.th "Post #{i} title") 82 | end 83 | end 84 | 85 | def display_search_results(objects) 86 | objects.limit(results_limit).reduce(String.new) do |string, object| 87 | string << (tag.tr display_search_results_row(object)) 88 | end 89 | end 90 | 91 | def display_search_results_row(object) 92 | user_column_fields.reduce(String.new) do |string, field| 93 | string << (tag.td object.send(field)) 94 | end 95 | .html_safe + 96 | display_user_posts(object.posts) 97 | end 98 | 99 | def display_user_posts(posts) 100 | posts.reduce(String.new) do |string, post| 101 | string << (tag.td truncate(post.title, length: post_title_length)) 102 | end 103 | .html_safe 104 | end 105 | end 106 | -------------------------------------------------------------------------------- /app/mailers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/activerecord-hackery/ransack_demo/e8d87eb29289256989e474a8c4c609466a63a893/app/mailers/.gitkeep -------------------------------------------------------------------------------- /app/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/activerecord-hackery/ransack_demo/e8d87eb29289256989e474a8c4c609466a63a893/app/models/.gitkeep -------------------------------------------------------------------------------- /app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | class ApplicationRecord < ActiveRecord::Base 2 | self.abstract_class = true 3 | 4 | # def self.ransackable_attributes(auth_object = nil) 5 | # unauthorized_ransackable_attributes 6 | # end 7 | 8 | def self.ransackable_associations(auth_object = nil) 9 | super # unauthorized_ransackable_associations 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/models/comment.rb: -------------------------------------------------------------------------------- 1 | class Comment < ApplicationRecord 2 | belongs_to :user 3 | belongs_to :post 4 | 5 | validates_presence_of :user, :post 6 | end 7 | -------------------------------------------------------------------------------- /app/models/post.rb: -------------------------------------------------------------------------------- 1 | class Post < ApplicationRecord 2 | extend PostsMixin 3 | 4 | belongs_to :user 5 | has_many :comments 6 | has_many :taggings, as: :taggable 7 | has_many :tags, through: :taggings 8 | 9 | validates_presence_of :user 10 | 11 | ransacker :title_diddly do |parent| 12 | Arel::Nodes::InfixOperation.new("||", parent.table[:title], "-diddly") 13 | end 14 | 15 | def tag_names=(names) 16 | self.tags = names.split(/,\s*/).map do |name| 17 | Tag.find_or_create_by(name: name) 18 | end 19 | end 20 | 21 | def tag_names 22 | tags.join(", ") 23 | end 24 | 25 | private 26 | 27 | def self.ransackable_attributes(_auth_object) 28 | ["title"] 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /app/models/posts_mixin.rb: -------------------------------------------------------------------------------- 1 | module PostsMixin 2 | def ransackable_attributes(_auth_object) 3 | ["title"] 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/models/role.rb: -------------------------------------------------------------------------------- 1 | class Role < ApplicationRecord 2 | has_and_belongs_to_many :users 3 | end 4 | -------------------------------------------------------------------------------- /app/models/tag.rb: -------------------------------------------------------------------------------- 1 | class Tag < ApplicationRecord 2 | has_many :taggings 3 | end 4 | -------------------------------------------------------------------------------- /app/models/tagging.rb: -------------------------------------------------------------------------------- 1 | class Tagging < ApplicationRecord 2 | belongs_to :tag 3 | belongs_to :taggable, polymorphic: true 4 | 5 | validates_presence_of :tag 6 | end 7 | -------------------------------------------------------------------------------- /app/models/user.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | class User < ApplicationRecord 3 | has_many :posts 4 | has_many :other_posts, class_name: "Post" 5 | has_many :comments 6 | has_and_belongs_to_many :roles 7 | 8 | def datetime_format 9 | "%d/%m/%y %H:%M" 10 | end 11 | 12 | def created 13 | created_at.strftime(datetime_format) 14 | end 15 | 16 | def updated 17 | updated_at.strftime(datetime_format) 18 | end 19 | 20 | def self.postgres_version 21 | connection.execute("select version()").to_a.first["version"].first(16) 22 | end 23 | 24 | private 25 | 26 | # Allowlist the User model attributes for sorting, except +password_digest+. 27 | # 28 | # The +full_name+ ransacker is also not included because error-prone in SQL 29 | # ORDER clauses and provided no additional functionality over +first_name+. 30 | # 31 | def self.ransortable_attributes(auth_object = nil) 32 | column_names - ["password_digest"] 33 | end 34 | 35 | # Allowlist the User model attributes for search, except +password_digest+, 36 | # as above. The +full_name+ ransacker below is included via +_ransackers.keys+ 37 | # 38 | def self.ransackable_attributes(auth_object = nil) 39 | ransortable_attributes + _ransackers.keys 40 | end 41 | 42 | # Allowlist the User model associations for sorting, only posts. 43 | # 44 | def self.ransackable_associations(auth_object = nil) 45 | ["posts", "other_posts"] 46 | end 47 | 48 | # Demonstration of using a "ransacker" (a virtual, searchable "column") to 49 | # allow searching via the full name from concatenated first and last names. 50 | # 51 | ransacker :full_name do |parent| 52 | Arel::Nodes::InfixOperation.new("||", 53 | Arel::Nodes::InfixOperation.new("||", 54 | parent.table[:first_name], Arel::Nodes.build_quoted(" ")), 55 | parent.table[:last_name]) 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | <%= tag.html do %> 3 | <%= tag.head do %> 4 | <%= tag.title 'RansackDemo' %> 5 | <%= stylesheet_link_tag 'application' %> 6 | <%= javascript_include_tag 'application' %> 7 | <%= csrf_meta_tags %> 8 | 13 | <% end %> 14 | 15 | <%= tag.body do %> 16 | 17 | <%= yield %> 18 | 19 | <%= tag.footer app_info %> 20 | <% end %> 21 | <% end %> 22 | -------------------------------------------------------------------------------- /app/views/users/_attribute_fields.erb: -------------------------------------------------------------------------------- 1 | <%= tag.span f.attribute_select(associations: user_posts_and_comments), 2 | class: :fields, 3 | 'data-object-name': f.object_name, 4 | escape: false %> 5 | -------------------------------------------------------------------------------- /app/views/users/_condition_fields.erb: -------------------------------------------------------------------------------- 1 | <%= tag.fieldset class: condition_fields, 2 | 'data-object-name': f.object_name do %> 3 | 4 | <%= tag.legend button_to_remove_fields %> 5 | 6 | <%= f.attribute_fields do |a| %> 7 | <%= render 'attribute_fields', f: a %> 8 | <% end %> 9 | 10 | <%= f.predicate_select %> 11 | 12 | <%= f.value_fields do |v| %> 13 | <%= render 'value_fields', f: v %> 14 | <% end %> 15 | 16 | <%= button_to_add_fields(f, :value) %> 17 | <% end %> 18 | -------------------------------------------------------------------------------- /app/views/users/_grouping_fields.erb: -------------------------------------------------------------------------------- 1 | <%= tag.fieldset class: :fields, 'data-object-name': f.object_name do %> 2 | 3 | <%= tag.legend "Match #{f.combinator_select} conditions #{ 4 | button_to_remove_fields}", escape: false %> 5 | 6 | <%= f.condition_fields do |c| %> 7 | <%= render 'condition_fields', f: c %> 8 | <% end %> 9 | 10 | <%= button_to_add_fields(f, :condition) %> 11 | 12 | <%= f.grouping_fields do |g| %> 13 | <%= render 'grouping_fields', f: g %> 14 | <% end %> 15 | 16 | <%= button_to_nest_fields(:grouping) %> 17 | 18 | <% end %> 19 | -------------------------------------------------------------------------------- /app/views/users/_results.erb: -------------------------------------------------------------------------------- 1 | <%= display_query_sql(@users) %> 2 | <%= tag.h2 display_results_header(@users.size) %> 3 | <%= tag.table do %> 4 | <%= tag.thead display_sort_column_headers(@search), escape: false %> 5 | <%= tag.tbody display_search_results(@users), escape: false %> 6 | <% end %> 7 | -------------------------------------------------------------------------------- /app/views/users/_sort_fields.erb: -------------------------------------------------------------------------------- 1 | <%= tag.span "#{f.sort_select} #{button_to_remove_fields}", 2 | class: :fields, 3 | 'data-object-name': f.object_name, 4 | escape: false %> 5 | -------------------------------------------------------------------------------- /app/views/users/_value_fields.erb: -------------------------------------------------------------------------------- 1 | <%= tag.span f.text_field(:value), 2 | class: value_fields, 3 | 'data-object-name': f.object_name, 4 | escape: false %> 5 | -------------------------------------------------------------------------------- /app/views/users/advanced_search.erb: -------------------------------------------------------------------------------- 1 | <%= tag.h1 'Advanced User Search' %> 2 | <%= tag.header link_to_toggle_search_modes %> 3 | 4 | <%= search_form_for( 5 | @search, 6 | url: advanced_search_users_path, 7 | html: { method: :post } 8 | ) do |f| %> 9 | 10 | <% setup_search_form(f) %> 11 | 12 | <%= tag.fieldset do %> 13 | <%= tag.legend 'Sorting' %> 14 | <%= f.sort_fields do |s| %> 15 | <%= render 'sort_fields', f: s %> 16 | <% end %> 17 | <%= button_to_add_fields(f, :sort) %> 18 | <% end %> 19 | 20 | <%= tag.fieldset do %> 21 | <%= tag.legend 'Condition Groups' %> 22 | <%= f.grouping_fields do |g| %> 23 | <%= render 'grouping_fields', f: g %> 24 | <% end %> 25 | <%= button_to_add_fields(f, :grouping) %> 26 | <% end %> 27 | 28 | <%= display_distinct_label_and_check_box %> 29 | <%= f.submit class: 'btn btn--invert' %> 30 | <% end %> 31 | 32 | <%= render 'results' %> 33 | -------------------------------------------------------------------------------- /app/views/users/index.erb: -------------------------------------------------------------------------------- 1 | <%= tag.h1 'Search Users' %> 2 | <%= tag.header link_to_toggle_search_modes %> 3 | 4 | <%= search_form_for @search do |f| %> 5 | 6 | <%= tag.fieldset do %> 7 | <%= tag.legend 'User' %> 8 | <%= tag.ul do %> 9 | <%= tag.li do %> 10 | <%= f.label :first_name_or_last_name_cont %> 11 | <%= f.text_field :first_name_or_last_name_cont %> 12 | <% end %> 13 | <%= tag.li do %> 14 | <%= f.label :email_cont %> 15 | <%= f.text_field :email_cont %> 16 | <% end %> 17 | <% end %> 18 | <% end %> 19 | 20 | <%= tag.fieldset do %> 21 | <%= tag.legend "User's Posts" %> 22 | <%= tag.ul do %> 23 | <%= tag.li do %> 24 | <%= f.label :posts_title_cont %> 25 | <%= f.text_field :posts_title_cont %> 26 | <% end %> 27 | 28 | <%= tag.li do %> 29 | <%= f.label :other_posts_title_cont %> 30 | <%= f.text_field :other_posts_title_cont %> 31 | <% end %> 32 | <% end %> 33 | <% end %> 34 | 35 | <%= display_distinct_label_and_check_box %> 36 | <%= f.submit class: 'btn btn--invert' %> 37 | <% end %> 38 | 39 | <%= render 'results' %> 40 | -------------------------------------------------------------------------------- /bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__) 3 | load Gem.bin_path("bundler", "bundle") 4 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path("../config/application", __dir__) 3 | require_relative "../config/boot" 4 | require "rails/commands" 5 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative "../config/boot" 3 | require "rake" 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require "fileutils" 3 | 4 | # path to your application root. 5 | APP_ROOT = File.expand_path("..", __dir__) 6 | 7 | def system!(*args) 8 | system(*args) || abort("\n== Command #{args} failed ==") 9 | end 10 | 11 | FileUtils.chdir APP_ROOT do 12 | # This script is a way to set up or update your development environment automatically. 13 | # This script is idempotent, so that you can run it at any time and get an expectable outcome. 14 | # Add necessary setup steps to this file. 15 | 16 | puts "== Installing dependencies ==" 17 | system! "gem install bundler --conservative" 18 | system("bundle check") || system!("bundle install") 19 | 20 | # puts "\n== Copying sample files ==" 21 | # unless File.exist?("config/database.yml") 22 | # FileUtils.cp "config/database.yml.sample", "config/database.yml" 23 | # end 24 | 25 | puts "\n== Preparing database ==" 26 | system! "bin/rails db:prepare" 27 | 28 | puts "\n== Removing old logs and tempfiles ==" 29 | system! "bin/rails log:clear tmp:clear" 30 | 31 | puts "\n== Restarting application server ==" 32 | system! "bin/rails restart" 33 | end 34 | -------------------------------------------------------------------------------- /bin/update: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require "pathname" 3 | require "fileutils" 4 | include FileUtils 5 | 6 | # path to your application root. 7 | APP_ROOT = Pathname.new File.expand_path("../../", __FILE__) 8 | 9 | def system!(*args) 10 | system(*args) || abort("\n== Command #{args} failed ==") 11 | end 12 | 13 | chdir APP_ROOT do 14 | # This script is a way to update your development environment automatically. 15 | # Add necessary update steps to this file. 16 | 17 | puts "== Installing dependencies ==" 18 | system! "gem install bundler --conservative" 19 | system("bundle check") || system!("bundle install") 20 | 21 | puts "\n== Updating database ==" 22 | system! "bin/rails db:migrate" 23 | 24 | puts "\n== Removing old logs and tempfiles ==" 25 | system! "bin/rails log:clear tmp:clear" 26 | 27 | puts "\n== Restarting application server ==" 28 | system! "bin/rails restart" 29 | end 30 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require_relative "config/environment" 4 | 5 | run Rails.application 6 | Rails.application.load_server 7 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | require_relative "boot" 2 | 3 | require "rails" 4 | # Pick the frameworks you want: 5 | require "active_model/railtie" 6 | require "active_job/railtie" 7 | require "active_record/railtie" 8 | # require "active_storage/engine" 9 | require "action_controller/railtie" 10 | # require "action_mailer/railtie" 11 | # require "action_mailbox/engine" 12 | # require "action_text/engine" 13 | require "action_view/railtie" 14 | # require "action_cable/engine" 15 | require "rails/test_unit/railtie" 16 | 17 | # Require the gems listed in Gemfile, including any gems 18 | # you've limited to :test, :development, or :production. 19 | Bundler.require(*Rails.groups) 20 | 21 | module RansackDemo 22 | class Application < Rails::Application 23 | # Initialize configuration defaults for originally generated Rails version. 24 | config.load_defaults 7.0 25 | 26 | # Configuration for the application, engines, and railties goes here. 27 | # 28 | # These settings can be overridden in specific environments using the files 29 | # in config/environments, which are processed later. 30 | # 31 | # config.time_zone = "Central Time (US & Canada)" 32 | # config.eager_load_paths << Rails.root.join("extras") 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) 2 | 3 | require "bundler/setup" # Set up gems listed in the Gemfile. 4 | -------------------------------------------------------------------------------- /config/credentials.yml: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key is used for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | 6 | # Make sure the secret is at least 30 characters and all random, 7 | # no regular words or you'll be exposed to dictionary attacks. 8 | # You can use `rails secret` to generate a secure secret key. 9 | 10 | # Make sure the secrets in this file are kept private 11 | # if you're sharing your code publicly. 12 | 13 | # Shared secrets are available across all environments. 14 | 15 | shared: 16 | api_key: 123 17 | 18 | # Environmental secrets are only available for that specific environment. 19 | 20 | development: 21 | secret_key_base: 21b854978ab40978d305219c753e6b289be12a0a008cf31679d55cdb054f90061aafe7312d83c71788eaccc6a996a2f626412f45a38a555b610ad594b301d620 22 | 23 | test: 24 | secret_key_base: 3dc469dda7679fc89774850563506a6defeaf26f37bd04017acd33bf8f16afb1eabfabf25eb09b54b886bbfa241a7b216da711c5ea48373ff8fc52b3e61552fe 25 | 26 | # Do not keep production secrets in the repository, 27 | # instead read values from the environment. 28 | 29 | production: 30 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> 31 | -------------------------------------------------------------------------------- /config/database.yml: -------------------------------------------------------------------------------- 1 | default: &default 2 | adapter: postgresql 3 | encoding: unicode 4 | # For details on connection pooling, see rails configuration guide 5 | # https://guides.rubyonrails.org/configuring.html#database-pooling 6 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> 7 | 8 | development: 9 | <<: *default 10 | database: ransack_demo_development 11 | 12 | # The specified database role being used to connect to postgres. 13 | # To create additional roles in postgres see `$ createuser --help`. 14 | # When left blank, postgres will use the default role. This is 15 | # the same name as the operating system user that initialized the database. 16 | #username: rails5 17 | 18 | # The password associated with the postgres role (username). 19 | #password: 20 | 21 | # Connect on a TCP socket. Omitted by default since the client uses a 22 | # domain socket that doesn't need configuration. Windows does not have 23 | # domain sockets, so uncomment these lines. 24 | #host: localhost 25 | 26 | # The TCP port the server listens on. Defaults to 5432. 27 | # If your server runs on a different port number, change accordingly. 28 | #port: 5432 29 | 30 | # Schema search path. The server defaults to $user,public 31 | #schema_search_path: myapp,sharedapp,public 32 | 33 | # Minimum log levels, in increasing order: 34 | # debug5, debug4, debug3, debug2, debug1, 35 | # log, notice, warning, error, fatal, and panic 36 | # Defaults to warning. 37 | #min_messages: notice 38 | 39 | # Warning: The database defined as "test" will be erased and 40 | # re-generated from your development database when you run "rake". 41 | # Do not set this db to the same as development or production. 42 | test: 43 | <<: *default 44 | database: ransack_demo_test 45 | 46 | # As with config/secrets.yml, you never want to store sensitive information, 47 | # like your database password, in your source code. If your source code is 48 | # ever seen by anyone, they now have access to your database. 49 | # 50 | # Instead, provide the password as a unix environment variable when you boot 51 | # the app. Read https://guides.rubyonrails.org/configuring.html#configuring-a-database 52 | # for a full rundown on how to provide these environment variables in a 53 | # production deployment. 54 | # 55 | # On Heroku and other platform providers, you may have a full connection URL 56 | # available as an environment variable. For example: 57 | # 58 | # DATABASE_URL="postgres://myuser:mypass@localhost/somedatabase" 59 | # 60 | # You can use this database configuration with: 61 | # 62 | # production: 63 | # url: <%= ENV['DATABASE_URL'] %> 64 | # 65 | production: 66 | <<: *default 67 | database: ransack_demo_production 68 | 69 | 70 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require_relative "application" 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /config/environments/development.rb: -------------------------------------------------------------------------------- 1 | require "active_support/core_ext/integer/time" 2 | 3 | Rails.application.configure do 4 | # Settings specified here will take precedence over those in config/application.rb. 5 | 6 | # In the development environment your application's code is reloaded any time 7 | # it changes. This slows down response time but is perfect for development 8 | # since you don't have to restart the web server when you make code changes. 9 | config.cache_classes = false 10 | 11 | # Do not eager load code on boot. 12 | config.eager_load = false 13 | 14 | # Show full error reports. 15 | config.consider_all_requests_local = true 16 | 17 | # Enable server timing 18 | config.server_timing = true 19 | 20 | # Enable/disable caching. By default caching is disabled. 21 | # Run rails dev:cache to toggle caching. 22 | if Rails.root.join("tmp/caching-dev.txt").exist? 23 | config.action_controller.perform_caching = true 24 | config.action_controller.enable_fragment_cache_logging = true 25 | 26 | config.cache_store = :memory_store 27 | config.public_file_server.headers = { 28 | "Cache-Control" => "public, max-age=#{2.days.to_i}" 29 | } 30 | else 31 | config.action_controller.perform_caching = false 32 | 33 | config.cache_store = :null_store 34 | end 35 | 36 | # Print deprecation notices to the Rails logger. 37 | config.active_support.deprecation = :log 38 | 39 | # Raise exceptions for disallowed deprecations. 40 | config.active_support.disallowed_deprecation = :raise 41 | 42 | # Tell Active Support which deprecation messages to disallow. 43 | config.active_support.disallowed_deprecation_warnings = :all 44 | 45 | # Raise an error on page load if there are pending migrations. 46 | config.active_record.migration_error = :page_load 47 | 48 | # Highlight code that triggered database queries in logs. 49 | config.active_record.verbose_query_logs = true 50 | 51 | # Suppress logger output for asset requests. 52 | config.assets.quiet = true 53 | 54 | # Raises error for missing translations. 55 | # config.i18n.raise_on_missing_translations = true 56 | 57 | # Annotate rendered view with file names. 58 | # config.action_view.annotate_rendered_view_with_filenames = true 59 | 60 | # Uncomment if you wish to allow Action Cable access from any origin. 61 | # config.action_cable.disable_request_forgery_protection = true 62 | end 63 | -------------------------------------------------------------------------------- /config/environments/production.rb: -------------------------------------------------------------------------------- 1 | require "active_support/core_ext/integer/time" 2 | 3 | Rails.application.configure do 4 | # Settings specified here will take precedence over those in config/application.rb. 5 | 6 | # Code is not reloaded between requests. 7 | config.cache_classes = true 8 | 9 | # Eager load code on boot. This eager loads most of Rails and 10 | # your application in memory, allowing both threaded web servers 11 | # and those relying on copy on write to perform better. 12 | # Rake tasks automatically ignore this option for performance. 13 | config.eager_load = true 14 | 15 | # Full error reports are disabled and caching is turned on. 16 | config.consider_all_requests_local = false 17 | config.action_controller.perform_caching = true 18 | 19 | # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] 20 | # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). 21 | # config.require_master_key = true 22 | 23 | # Disable serving static files from the `/public` folder by default since 24 | # Apache or NGINX already handles this. 25 | config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? 26 | 27 | # Compress CSS using a preprocessor. 28 | # config.assets.css_compressor = :sass 29 | 30 | # Do not fallback to assets pipeline if a precompiled asset is missed. 31 | config.assets.compile = false 32 | 33 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 34 | # config.asset_host = "http://assets.example.com" 35 | 36 | # Specifies the header that your server uses for sending files. 37 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache 38 | # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX 39 | config.action_dispatch.x_sendfile_header = nil # for Heroku 40 | 41 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 42 | # config.force_ssl = true 43 | 44 | # Use the lowest log level to ensure availability of diagnostic information 45 | # when problems arise. 46 | config.log_level = :debug 47 | 48 | # Prepend all log lines with the following tags. 49 | config.log_tags = [ :request_id ] 50 | 51 | # Use a different cache store in production. 52 | # config.cache_store = :mem_cache_store 53 | 54 | # Use a real queuing backend for Active Job (and separate queues per environment). 55 | # config.active_job.queue_adapter = :resque 56 | # config.active_job.queue_name_prefix = "ransack_demo_production" 57 | 58 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 59 | # the I18n.default_locale when a translation cannot be found). 60 | config.i18n.fallbacks = true 61 | 62 | # Don't log any deprecations. 63 | config.active_support.report_deprecations = false 64 | 65 | # Use default logging formatter so that PID and timestamp are not suppressed. 66 | config.log_formatter = ::Logger::Formatter.new 67 | 68 | # Use a different logger for distributed setups. 69 | # require "syslog/logger" 70 | # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") 71 | 72 | if ENV["RAILS_LOG_TO_STDOUT"].present? 73 | logger = ActiveSupport::Logger.new(STDOUT) 74 | logger.formatter = config.log_formatter 75 | config.logger = ActiveSupport::TaggedLogging.new(logger) 76 | end 77 | 78 | # Do not dump schema after migrations. 79 | config.active_record.dump_schema_after_migration = false 80 | end 81 | -------------------------------------------------------------------------------- /config/environments/test.rb: -------------------------------------------------------------------------------- 1 | require "active_support/core_ext/integer/time" 2 | 3 | # The test environment is used exclusively to run your application's 4 | # test suite. You never need to work with it otherwise. Remember that 5 | # your test database is "scratch space" for the test suite and is wiped 6 | # and recreated between test runs. Don't rely on the data there! 7 | 8 | Rails.application.configure do 9 | # Settings specified here will take precedence over those in config/application.rb. 10 | 11 | # Turn false under Spring and add config.action_view.cache_template_loading = true. 12 | config.cache_classes = true 13 | 14 | # Eager loading loads your whole application. When running a single test locally, 15 | # this probably isn't necessary. It's a good idea to do in a continuous integration 16 | # system, or in some way before deploying your code. 17 | config.eager_load = ENV["CI"].present? 18 | 19 | # Configure public file server for tests with Cache-Control for performance. 20 | config.public_file_server.enabled = true 21 | config.public_file_server.headers = { 22 | "Cache-Control" => "public, max-age=#{1.hour.to_i}" 23 | } 24 | 25 | # Show full error reports and disable caching. 26 | config.consider_all_requests_local = true 27 | config.action_controller.perform_caching = false 28 | config.cache_store = :null_store 29 | 30 | # Raise exceptions instead of rendering exception templates. 31 | config.action_dispatch.show_exceptions = false 32 | 33 | # Disable request forgery protection in test environment. 34 | config.action_controller.allow_forgery_protection = false 35 | 36 | # Print deprecation notices to the stderr. 37 | config.active_support.deprecation = :stderr 38 | 39 | # Raise exceptions for disallowed deprecations. 40 | config.active_support.disallowed_deprecation = :raise 41 | 42 | # Tell Active Support which deprecation messages to disallow. 43 | config.active_support.disallowed_deprecation_warnings = :all 44 | 45 | # Raises error for missing translations. 46 | # config.i18n.raise_on_missing_translations = true 47 | 48 | # Annotate rendered view with file names. 49 | # config.action_view.annotate_rendered_view_with_filenames = true 50 | end 51 | -------------------------------------------------------------------------------- /config/initializers/application_controller_renderer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # ActiveSupport::Reloader.to_prepare do 4 | # ApplicationController.renderer.defaults.merge!( 5 | # http_host: 'example.org', 6 | # https: false 7 | # ) 8 | # end 9 | -------------------------------------------------------------------------------- /config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | Rails.application.config.assets.version = "1.3" 5 | 6 | # Add additional assets to the asset load path. 7 | # Rails.application.config.assets.paths << Emoji.images_path 8 | 9 | # Precompile additional assets. 10 | # application.js, application.css, and all non-JS/CSS in the app/assets 11 | # folder are already added. 12 | # Rails.application.config.assets.precompile += %w( admin.js admin.css ) 13 | -------------------------------------------------------------------------------- /config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| /my_noisy_library/.match?(line) } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code 7 | # by setting BACKTRACE=1 before calling your invocation, like "BACKTRACE=1 ./bin/rails runner 'MyClass.perform'". 8 | Rails.backtrace_cleaner.remove_silencers! if ENV["BACKTRACE"] 9 | -------------------------------------------------------------------------------- /config/initializers/content_security_policy.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Define an application-wide content security policy. 4 | # See the Securing Rails Applications Guide for more information: 5 | # https://guides.rubyonrails.org/security.html#content-security-policy-header 6 | 7 | # Rails.application.configure do 8 | # config.content_security_policy do |policy| 9 | # policy.default_src :self, :https 10 | # policy.font_src :self, :https, :data 11 | # policy.img_src :self, :https, :data 12 | # policy.object_src :none 13 | # policy.script_src :self, :https 14 | # policy.style_src :self, :https 15 | # # Specify URI for violation reports 16 | # # policy.report_uri "/csp-violation-report-endpoint" 17 | # end 18 | # 19 | # # Generate session nonces for permitted importmap and inline scripts 20 | # config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s } 21 | # config.content_security_policy_nonce_directives = %w(script-src) 22 | # 23 | # # Report violations without enforcing the policy. 24 | # # config.content_security_policy_report_only = true 25 | # end 26 | -------------------------------------------------------------------------------- /config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Specify a serializer for the signed and encrypted cookie jars. 4 | # Valid options are :json, :marshal, and :hybrid. 5 | Rails.application.config.action_dispatch.cookies_serializer = :json 6 | -------------------------------------------------------------------------------- /config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure parameters to be filtered from the log file. Use this to limit dissemination of 4 | # sensitive information. See the ActiveSupport::ParameterFilter documentation for supported 5 | # notations and behaviors. 6 | Rails.application.config.filter_parameters += [ 7 | :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn 8 | ] 9 | -------------------------------------------------------------------------------- /config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, "\\1en" 8 | # inflect.singular /^(ox)en/i, "\\1" 9 | # inflect.irregular "person", "people" 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym "RESTful" 16 | # end 17 | -------------------------------------------------------------------------------- /config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | -------------------------------------------------------------------------------- /config/initializers/new_framework_defaults_7_1.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | # 3 | # This file eases your Rails 7.1 framework defaults upgrade. 4 | # 5 | # Uncomment each configuration one by one to switch to the new default. 6 | # Once your application is ready to run with all new defaults, you can remove 7 | # this file and set the `config.load_defaults` to `7.1`. 8 | # 9 | # Read the Guide for Upgrading Ruby on Rails for more info on each option. 10 | # https://guides.rubyonrails.org/upgrading_ruby_on_rails.html 11 | 12 | ### 13 | # No longer add autoloaded paths into `$LOAD_PATH`. This means that you won't be able 14 | # to manually require files that are managed by the autoloader, which you shouldn't do anyway. 15 | # 16 | # This will reduce the size of the load path, making `require` faster if you don't use bootsnap, or reduce the size 17 | # of the bootsnap cache if you use it. 18 | # 19 | # To set this configuration, add the following line to `config/application.rb` (NOT this file): 20 | # config.add_autoload_paths_to_load_path = false 21 | 22 | ### 23 | # Remove the default X-Download-Options headers since it is used only by Internet Explorer. 24 | # If you need to support Internet Explorer, add back `"X-Download-Options" => "noopen"`. 25 | #++ 26 | # Rails.application.config.action_dispatch.default_headers = { 27 | # "X-Frame-Options" => "SAMEORIGIN", 28 | # "X-XSS-Protection" => "0", 29 | # "X-Content-Type-Options" => "nosniff", 30 | # "X-Permitted-Cross-Domain-Policies" => "none", 31 | # "Referrer-Policy" => "strict-origin-when-cross-origin" 32 | # } 33 | 34 | ### 35 | # Do not treat an `ActionController::Parameters` instance 36 | # as equal to an equivalent `Hash` by default. 37 | #++ 38 | # Rails.application.config.action_controller.allow_deprecated_parameters_hash_equality = false 39 | 40 | ### 41 | # Active Record Encryption now uses SHA-256 as its hash digest algorithm. 42 | # 43 | # There are 3 scenarios to consider. 44 | # 45 | # 1. If you have data encrypted with previous Rails versions, and you have 46 | # +config.active_support.key_generator_hash_digest_class+ configured as SHA1 (the default 47 | # before Rails 7.0), you need to configure SHA-1 for Active Record Encryption too: 48 | #++ 49 | # Rails.application.config.active_record.encryption.hash_digest_class = OpenSSL::Digest::SHA1 50 | # 51 | # 2. If you have +config.active_support.key_generator_hash_digest_class+ configured as SHA256 (the new default 52 | # in 7.0), then you need to configure SHA-256 for Active Record Encryption: 53 | #++ 54 | # Rails.application.config.active_record.encryption.hash_digest_class = OpenSSL::Digest::SHA256 55 | # 56 | # 3. If you don't currently have data encrypted with Active Record encryption, you can disable this setting to 57 | # configure the default behavior starting 7.1+: 58 | #++ 59 | # Rails.application.config.active_record.encryption.support_sha1_for_non_deterministic_encryption = false 60 | 61 | ### 62 | # No longer run after_commit callbacks on the first of multiple Active Record 63 | # instances to save changes to the same database row within a transaction. 64 | # Instead, run these callbacks on the instance most likely to have internal 65 | # state which matches what was committed to the database, typically the last 66 | # instance to save. 67 | #++ 68 | # Rails.application.config.active_record.run_commit_callbacks_on_first_saved_instances_in_transaction = false 69 | 70 | ### 71 | # Configures SQLite with a strict strings mode, which disables double-quoted string literals. 72 | # 73 | # SQLite has some quirks around double-quoted string literals. 74 | # It first tries to consider double-quoted strings as identifier names, but if they don't exist 75 | # it then considers them as string literals. Because of this, typos can silently go unnoticed. 76 | # For example, it is possible to create an index for a non existing column. 77 | # See https://www.sqlite.org/quirks.html#double_quoted_string_literals_are_accepted for more details. 78 | #++ 79 | # Rails.application.config.active_record.sqlite3_adapter_strict_strings_by_default = true 80 | 81 | ### 82 | # Disable deprecated singular associations names. 83 | #++ 84 | # Rails.application.config.active_record.allow_deprecated_singular_associations_name = false 85 | 86 | ### 87 | # Enable the Active Job `BigDecimal` argument serializer, which guarantees 88 | # roundtripping. Without this serializer, some queue adapters may serialize 89 | # `BigDecimal` arguments as simple (non-roundtrippable) strings. 90 | # 91 | # When deploying an application with multiple replicas, old (pre-Rails 7.1) 92 | # replicas will not be able to deserialize `BigDecimal` arguments from this 93 | # serializer. Therefore, this setting should only be enabled after all replicas 94 | # have been successfully upgraded to Rails 7.1. 95 | #++ 96 | # Rails.application.config.active_job.use_big_decimal_serializer = true 97 | 98 | ### 99 | # Specify if an `ArgumentError` should be raised if `Rails.cache` `fetch` or 100 | # `write` are given an invalid `expires_at` or `expires_in` time. 101 | # Options are `true`, and `false`. If `false`, the exception will be reported 102 | # as `handled` and logged instead. 103 | #++ 104 | # Rails.application.config.active_support.raise_on_invalid_cache_expiration_time = true 105 | 106 | ### 107 | # Specify whether Query Logs will format tags using the SQLCommenter format 108 | # (https://open-telemetry.github.io/opentelemetry-sqlcommenter/), or using the legacy format. 109 | # Options are `:legacy` and `:sqlcommenter`. 110 | #++ 111 | # Rails.application.config.active_record.query_log_tags_format = :sqlcommenter 112 | 113 | ### 114 | # Specify the default serializer used by `MessageEncryptor` and `MessageVerifier` 115 | # instances. 116 | # 117 | # The legacy default is `:marshal`, which is a potential vector for 118 | # deserialization attacks in cases where a message signing secret has been 119 | # leaked. 120 | # 121 | # In Rails 7.1, the new default is `:json_allow_marshal` which serializes and 122 | # deserializes with `ActiveSupport::JSON`, but can fall back to deserializing 123 | # with `Marshal` so that legacy messages can still be read. 124 | # 125 | # In Rails 7.2, the default will become `:json` which serializes and 126 | # deserializes with `ActiveSupport::JSON` only. 127 | # 128 | # Alternatively, you can choose `:message_pack` or `:message_pack_allow_marshal`, 129 | # which serialize with `ActiveSupport::MessagePack`. `ActiveSupport::MessagePack` 130 | # can roundtrip some Ruby types that are not supported by JSON, and may provide 131 | # improved performance, but it requires the `msgpack` gem. 132 | # 133 | # For more information, see 134 | # https://guides.rubyonrails.org/v7.1/configuring.html#config-active-support-message-serializer 135 | # 136 | # If you are performing a rolling deploy of a Rails 7.1 upgrade, wherein servers 137 | # that have not yet been upgraded must be able to read messages from upgraded 138 | # servers, first deploy without changing the serializer, then set the serializer 139 | # in a subsequent deploy. 140 | #++ 141 | # Rails.application.config.active_support.message_serializer = :json_allow_marshal 142 | 143 | ### 144 | # Enable a performance optimization that serializes message data and metadata 145 | # together. This changes the message format, so messages serialized this way 146 | # cannot be read by older versions of Rails. However, messages that use the old 147 | # format can still be read, regardless of whether this optimization is enabled. 148 | # 149 | # To perform a rolling deploy of a Rails 7.1 upgrade, wherein servers that have 150 | # not yet been upgraded must be able to read messages from upgraded servers, 151 | # leave this optimization off on the first deploy, then enable it on a 152 | # subsequent deploy. 153 | #++ 154 | # Rails.application.config.active_support.use_message_serializer_for_metadata = true 155 | 156 | ### 157 | # Set the maximum size for Rails log files. 158 | # 159 | # `config.load_defaults 7.1` does not set this value for environments other than 160 | # development and test. 161 | #++ 162 | # if Rails.env.local? 163 | # Rails.application.config.log_file_size = 100 * 1024 * 1024 164 | # end 165 | 166 | ### 167 | # Enable raising on assignment to attr_readonly attributes. The previous 168 | # behavior would allow assignment but silently not persist changes to the 169 | # database. 170 | #++ 171 | # Rails.application.config.active_record.raise_on_assign_to_attr_readonly = true 172 | 173 | ### 174 | # Enable validating only parent-related columns for presence when the parent is mandatory. 175 | # The previous behavior was to validate the presence of the parent record, which performed an extra query 176 | # to get the parent every time the child record was updated, even when parent has not changed. 177 | #++ 178 | # Rails.application.config.active_record.belongs_to_required_validates_foreign_key = false 179 | 180 | ### 181 | # Enable precompilation of `config.filter_parameters`. Precompilation can 182 | # improve filtering performance, depending on the quantity and types of filters. 183 | #++ 184 | # Rails.application.config.precompile_filter_parameters = true 185 | 186 | ### 187 | # Enable before_committed! callbacks on all enrolled records in a transaction. 188 | # The previous behavior was to only run the callbacks on the first copy of a record 189 | # if there were multiple copies of the same record enrolled in the transaction. 190 | #++ 191 | # Rails.application.config.active_record.before_committed_on_all_records = true 192 | 193 | ### 194 | # Disable automatic column serialization into YAML. 195 | # To keep the historic behavior, you can set it to `YAML`, however it is 196 | # recommended to explicitly define the serialization method for each column 197 | # rather than to rely on a global default. 198 | #++ 199 | # Rails.application.config.active_record.default_column_serializer = nil 200 | 201 | ### 202 | # Enable a performance optimization that serializes Active Record models 203 | # in a faster and more compact way. 204 | # 205 | # To perform a rolling deploy of a Rails 7.1 upgrade, wherein servers that have 206 | # not yet been upgraded must be able to read caches from upgraded servers, 207 | # leave this optimization off on the first deploy, then enable it on a 208 | # subsequent deploy. 209 | #++ 210 | # Rails.application.config.active_record.marshalling_format_version = 7.1 211 | 212 | ### 213 | # Run `after_commit` and `after_*_commit` callbacks in the order they are defined in a model. 214 | # This matches the behaviour of all other callbacks. 215 | # In previous versions of Rails, they ran in the inverse order. 216 | #++ 217 | # Rails.application.config.active_record.run_after_transaction_callbacks_in_order_defined = true 218 | 219 | ### 220 | # Whether a `transaction` block is committed or rolled back when exited via `return`, `break` or `throw`. 221 | #++ 222 | # Rails.application.config.active_record.commit_transaction_on_non_local_return = true 223 | 224 | ### 225 | # Controls when to generate a value for has_secure_token declarations. 226 | #++ 227 | # Rails.application.config.active_record.generate_secure_token_on = :initialize 228 | 229 | ### 230 | # ** Please read carefully, this must be configured in config/application.rb ** 231 | # 232 | # Change the format of the cache entry. 233 | # 234 | # Changing this default means that all new cache entries added to the cache 235 | # will have a different format that is not supported by Rails 7.0 236 | # applications. 237 | # 238 | # Only change this value after your application is fully deployed to Rails 7.1 239 | # and you have no plans to rollback. 240 | # When you're ready to change format, add this to `config/application.rb` (NOT 241 | # this file): 242 | # config.active_support.cache_format_version = 7.1 243 | 244 | ### 245 | # Configure Action View to use HTML5 standards-compliant sanitizers when they are supported on your 246 | # platform. 247 | # 248 | # `Rails::HTML::Sanitizer.best_supported_vendor` will cause Action View to use HTML5-compliant 249 | # sanitizers if they are supported, else fall back to HTML4 sanitizers. 250 | # 251 | # In previous versions of Rails, Action View always used `Rails::HTML4::Sanitizer` as its vendor. 252 | #++ 253 | # Rails.application.config.action_view.sanitizer_vendor = Rails::HTML::Sanitizer.best_supported_vendor 254 | 255 | ### 256 | # Configure Action Text to use an HTML5 standards-compliant sanitizer when it is supported on your 257 | # platform. 258 | # 259 | # `Rails::HTML::Sanitizer.best_supported_vendor` will cause Action Text to use HTML5-compliant 260 | # sanitizers if they are supported, else fall back to HTML4 sanitizers. 261 | # 262 | # In previous versions of Rails, Action Text always used `Rails::HTML4::Sanitizer` as its vendor. 263 | #++ 264 | # Rails.application.config.action_text.sanitizer_vendor = Rails::HTML::Sanitizer.best_supported_vendor 265 | 266 | ### 267 | # Configure the log level used by the DebugExceptions middleware when logging 268 | # uncaught exceptions during requests. 269 | #++ 270 | # Rails.application.config.action_dispatch.debug_exception_log_level = :error 271 | 272 | ### 273 | # Configure the test helpers in Action View, Action Dispatch, and rails-dom-testing to use HTML5 274 | # parsers. 275 | # 276 | # Nokogiri::HTML5 isn't supported on JRuby, so JRuby applications must set this to :html4. 277 | # 278 | # In previous versions of Rails, these test helpers always used an HTML4 parser. 279 | #++ 280 | # Rails.application.config.dom_testing_default_html_version = :html5 281 | -------------------------------------------------------------------------------- /config/initializers/permissions_policy.rb: -------------------------------------------------------------------------------- 1 | # Define an application-wide HTTP permissions policy. For further 2 | # information see https://developers.google.com/web/updates/2018/06/feature-policy 3 | # 4 | # Rails.application.config.permissions_policy do |f| 5 | # f.camera :none 6 | # f.gyroscope :none 7 | # f.microphone :none 8 | # f.usb :none 9 | # f.fullscreen :self 10 | # f.payment :self, "https://secure.example.com" 11 | # end 12 | -------------------------------------------------------------------------------- /config/initializers/secret_token.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | # Make sure the secret is at least 30 characters and all random, 6 | # no regular words or you'll be exposed to dictionary attacks. 7 | RansackDemo::Application.config.secret_token = "72292a5bd6e94a4f757cb86c273b7beda0fb4c33830b879d3a0a0f862b3991d497acec9eb0fe0b37c24f90daf6ff35afae0cfda2a4e9efff8c96616b11dad108" 8 | -------------------------------------------------------------------------------- /config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | RansackDemo::Application.config.session_store :cookie_store, key: "_ransack_demo_session" 4 | 5 | # Use the database for sessions instead of the cookie-based default, 6 | # which shouldn't be used to store highly confidential information 7 | # (create the session table with "rails generate session_migration") 8 | # RansackDemo::Application.config.session_store :active_record_store 9 | -------------------------------------------------------------------------------- /config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # The following keys must be escaped otherwise they will not be retrieved by 20 | # the default I18n backend: 21 | # 22 | # true, false, on, off, yes, no 23 | # 24 | # Instead, surround them with single quotes. 25 | # 26 | # en: 27 | # 'true': 'foo' 28 | # 29 | # To learn more, please read the Rails Internationalization guide 30 | # available at https://guides.rubyonrails.org/i18n.html. 31 | 32 | en: 33 | hello: "Hello world" 34 | 35 | ransack: 36 | associations: 37 | user: 38 | other_posts: Another Post 39 | -------------------------------------------------------------------------------- /config/puma.rb: -------------------------------------------------------------------------------- 1 | # Puma can serve each request in a thread from an internal thread pool. 2 | # The `threads` method setting takes two numbers: a minimum and maximum. 3 | # Any libraries that use thread pools should be configured to match 4 | # the maximum value specified for Puma. Default is set to 5 threads for minimum 5 | # and maximum; this matches the default thread size of Active Record. 6 | # 7 | max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } 8 | min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } 9 | threads min_threads_count, max_threads_count 10 | 11 | # Specifies the `worker_timeout` threshold that Puma will use to wait before 12 | # terminating a worker in development environments. 13 | # 14 | worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" 15 | 16 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000. 17 | # 18 | port ENV.fetch("PORT") { 3000 } 19 | 20 | # Specifies the `environment` that Puma will run in. 21 | # 22 | environment ENV.fetch("RAILS_ENV") { "development" } 23 | 24 | # Specifies the `pidfile` that Puma will use. 25 | pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } 26 | 27 | # Specifies the number of `workers` to boot in clustered mode. 28 | # Workers are forked web server processes. If using threads and workers together 29 | # the concurrency of the application would be max `threads` * `workers`. 30 | # Workers do not work on JRuby or Windows (both of which do not support 31 | # processes). 32 | # 33 | # workers ENV.fetch("WEB_CONCURRENCY") { 2 } 34 | 35 | # Use the `preload_app!` method when specifying a `workers` number. 36 | # This directive tells Puma to first boot the application and load code 37 | # before forking the application. This takes advantage of Copy On Write 38 | # process behavior so workers use less memory. 39 | # 40 | # preload_app! 41 | 42 | # Allow puma to be restarted by `rails restart` command. 43 | plugin :tmp_restart 44 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | resources :users, only: :index do 3 | match "advanced_search" => "users#advanced_search", 4 | on: :collection, via: [:get, :post], as: :advanced_search 5 | end 6 | root to: "users#index" 7 | # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html 8 | end 9 | -------------------------------------------------------------------------------- /config/spring.rb: -------------------------------------------------------------------------------- 1 | %w[ 2 | .ruby-version 3 | .rbenv-vars 4 | tmp/restart.txt 5 | tmp/caching-dev.txt 6 | ].each { |path| Spring.watch(path) } 7 | -------------------------------------------------------------------------------- /db/migrate/20110609001909_create_users.rb: -------------------------------------------------------------------------------- 1 | class CreateUsers < ActiveRecord::Migration[6.0] 2 | def change 3 | create_table :users do |t| 4 | t.string :first_name 5 | t.string :last_name 6 | t.string :email 7 | t.string :password_digest 8 | 9 | t.timestamps 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20110609002030_create_posts.rb: -------------------------------------------------------------------------------- 1 | class CreatePosts < ActiveRecord::Migration[6.0] 2 | def change 3 | create_table :posts do |t| 4 | t.belongs_to :user 5 | t.string :title 6 | t.text :body 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20110609002121_create_comments.rb: -------------------------------------------------------------------------------- 1 | class CreateComments < ActiveRecord::Migration[6.0] 2 | def change 3 | create_table :comments do |t| 4 | t.belongs_to :user 5 | t.belongs_to :post 6 | t.text :body 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20110609002140_create_roles.rb: -------------------------------------------------------------------------------- 1 | class CreateRoles < ActiveRecord::Migration[6.0] 2 | def change 3 | create_table :roles do |t| 4 | t.string :name 5 | t.string :description 6 | 7 | t.timestamps 8 | end 9 | 10 | create_table :roles_users, :id => false do |t| 11 | t.belongs_to :role 12 | t.belongs_to :user 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /db/migrate/20110609002232_create_tags.rb: -------------------------------------------------------------------------------- 1 | class CreateTags < ActiveRecord::Migration[6.0] 2 | def change 3 | create_table :tags do |t| 4 | t.string :name 5 | 6 | t.timestamps 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20110609002321_create_taggings.rb: -------------------------------------------------------------------------------- 1 | class CreateTaggings < ActiveRecord::Migration[6.0] 2 | def change 3 | create_table :taggings do |t| 4 | t.belongs_to :tag 5 | t.integer :taggable_id 6 | t.string :taggable_type 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/schema.rb: -------------------------------------------------------------------------------- 1 | # This file is auto-generated from the current state of the database. Instead 2 | # of editing this file, please use the migrations feature of Active Record to 3 | # incrementally modify your database, and then regenerate this schema definition. 4 | # 5 | # This file is the source Rails uses to define your schema when running `bin/rails 6 | # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to 7 | # be faster and is potentially less error prone than running all of your 8 | # migrations from scratch. Old migrations may fail to apply correctly if those 9 | # migrations use external dependencies or application code. 10 | # 11 | # It's strongly recommended that you check this file into your version control system. 12 | 13 | ActiveRecord::Schema[7.1].define(version: 2011_06_09_002321) do 14 | # These are extensions that must be enabled in order to support this database 15 | enable_extension "plpgsql" 16 | 17 | create_table "comments", force: :cascade do |t| 18 | t.bigint "user_id" 19 | t.bigint "post_id" 20 | t.text "body" 21 | t.datetime "created_at", null: false 22 | t.datetime "updated_at", null: false 23 | t.index ["post_id"], name: "index_comments_on_post_id" 24 | t.index ["user_id"], name: "index_comments_on_user_id" 25 | end 26 | 27 | create_table "posts", force: :cascade do |t| 28 | t.bigint "user_id" 29 | t.string "title" 30 | t.text "body" 31 | t.datetime "created_at", null: false 32 | t.datetime "updated_at", null: false 33 | t.index ["user_id"], name: "index_posts_on_user_id" 34 | end 35 | 36 | create_table "roles", force: :cascade do |t| 37 | t.string "name" 38 | t.string "description" 39 | t.datetime "created_at", null: false 40 | t.datetime "updated_at", null: false 41 | end 42 | 43 | create_table "roles_users", id: false, force: :cascade do |t| 44 | t.bigint "role_id" 45 | t.bigint "user_id" 46 | t.index ["role_id"], name: "index_roles_users_on_role_id" 47 | t.index ["user_id"], name: "index_roles_users_on_user_id" 48 | end 49 | 50 | create_table "taggings", force: :cascade do |t| 51 | t.bigint "tag_id" 52 | t.integer "taggable_id" 53 | t.string "taggable_type" 54 | t.datetime "created_at", null: false 55 | t.datetime "updated_at", null: false 56 | t.index ["tag_id"], name: "index_taggings_on_tag_id" 57 | end 58 | 59 | create_table "tags", force: :cascade do |t| 60 | t.string "name" 61 | t.datetime "created_at", null: false 62 | t.datetime "updated_at", null: false 63 | end 64 | 65 | create_table "users", force: :cascade do |t| 66 | t.string "first_name" 67 | t.string "last_name" 68 | t.string "email" 69 | t.string "password_digest" 70 | t.datetime "created_at", null: false 71 | t.datetime "updated_at", null: false 72 | end 73 | 74 | end 75 | -------------------------------------------------------------------------------- /db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) 7 | # Mayor.create(name: 'Emanuel', city: cities.first) 8 | require "factory_bot" 9 | 10 | role = {} 11 | 12 | role[:admin] = Role.create(name: "admin", description: "Superuser.") 13 | 14 | role[:moderator] = Role.create( 15 | name: "moderator", 16 | description: "Can moderate comments." 17 | ) 18 | 19 | role[:user] = Role.create(name: "user", description: "A plain old user.") 20 | 21 | FactoryBot.define do 22 | factory :user do 23 | first_name { Faker::Name.first_name } 24 | last_name { Faker::Name.last_name } 25 | roles { ["user"] } 26 | email { 27 | "#{self.first_name.downcase}-#{self.last_name.downcase}@example.com" 28 | } 29 | end 30 | 31 | factory :post do 32 | title { Faker::Lorem.sentence( 33 | word_count: 1, supplemental: false, random_words_to_add: 0) 34 | } 35 | body { Faker::Lorem.paragraph } 36 | tag_names { Faker::Lorem.words(number: 3).join(",") } 37 | end 38 | 39 | commenters = 1.upto(3).map { FactoryBot.create(:user, roles: [role[:user]]) } 40 | 41 | factory :comment do 42 | user { commenters.sample } 43 | body { Faker::Lorem.paragraph } 44 | end 45 | end 46 | 47 | 10.times do 48 | user = FactoryBot.create(:user, roles: [role[:admin]]) 49 | putc '.' 50 | 3.times do 51 | post = FactoryBot.create(:post, user: user) 52 | putc '.' 53 | 3.times { 54 | FactoryBot.create(:comment, post: post) 55 | putc '.' 56 | } 57 | end 58 | end 59 | 60 | User.all.each do |user| 61 | r = rand(100_000) 62 | created, updated = r.minutes.from_now, (r + rand(10_000)).minutes.from_now 63 | user.update_columns(created_at: created, updated_at: updated) 64 | end 65 | -------------------------------------------------------------------------------- /doc/README_FOR_APP: -------------------------------------------------------------------------------- 1 | Use this README file to introduce your application and point to useful places in the API for learning more. 2 | Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries. 3 | -------------------------------------------------------------------------------- /lib/tasks/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/activerecord-hackery/ransack_demo/e8d87eb29289256989e474a8c4c609466a63a893/lib/tasks/.gitkeep -------------------------------------------------------------------------------- /log/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/activerecord-hackery/ransack_demo/e8d87eb29289256989e474a8c4c609466a63a893/log/.gitkeep -------------------------------------------------------------------------------- /public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |You may have mistyped the address or the page may have moved.
63 |If you are the application owner check the logs for more information.
65 |Maybe you tried to change something you didn't have access to.
63 |If you are the application owner check the logs for more information.
65 |If you are the application owner check the logs for more information.
64 |