├── .coveralls.yml ├── .gitignore ├── .rspec ├── .travis.yml ├── Appraisals ├── Gemfile ├── Gemfile.lock ├── HISTORY ├── MIT-LICENSE ├── README.md ├── Rakefile ├── app └── models │ ├── .gitkeep │ ├── redirect_rule.rb │ └── request_environment_rule.rb ├── db └── migrate │ ├── 20120815212612_create_redirect_rules.rb │ └── 20120823163756_create_request_environment_rules.rb ├── gemfiles ├── rails_31.gemfile ├── rails_31.gemfile.lock ├── rails_32.gemfile ├── rails_32.gemfile.lock ├── rails_40.gemfile ├── rails_40.gemfile.lock ├── rails_41.gemfile ├── rails_41.gemfile.lock ├── rails_419.gemfile ├── rails_419.gemfile.lock ├── rails_42.gemfile ├── rails_42.gemfile.lock ├── rails_50.gemfile ├── rails_50.gemfile.lock ├── rails_51.gemfile └── rails_51.gemfile.lock ├── lib ├── redirector.rb └── redirector │ ├── engine.rb │ ├── middleware.rb │ ├── regex_attribute.rb │ └── version.rb ├── redirector.gemspec ├── script └── rails ├── spec ├── dummy │ ├── README.rdoc │ ├── Rakefile │ ├── app │ │ ├── assets │ │ │ ├── javascripts │ │ │ │ └── application.js │ │ │ └── stylesheets │ │ │ │ └── application.css │ │ ├── controllers │ │ │ ├── application_controller.rb │ │ │ └── news_controller.rb │ │ ├── helpers │ │ │ └── application_helper.rb │ │ ├── mailers │ │ │ └── .gitkeep │ │ ├── models │ │ │ └── .gitkeep │ │ └── views │ │ │ └── layouts │ │ │ └── application.html.erb │ ├── config.ru │ ├── config │ │ ├── application.rb │ │ ├── boot.rb │ │ ├── database.travis.yml │ │ ├── database.yml.example │ │ ├── environment.rb │ │ ├── environments │ │ │ ├── development.rb │ │ │ ├── production.rb │ │ │ └── test.rb │ │ ├── initializers │ │ │ ├── backtrace_silencers.rb │ │ │ ├── inflections.rb │ │ │ ├── mime_types.rb │ │ │ ├── secret_token.rb │ │ │ ├── session_store.rb │ │ │ └── wrap_parameters.rb │ │ ├── locales │ │ │ └── en.yml │ │ └── routes.rb │ ├── db │ │ └── schema.rb │ ├── lib │ │ └── assets │ │ │ └── .gitkeep │ ├── log │ │ └── .gitkeep │ ├── public │ │ ├── 404.html │ │ ├── 422.html │ │ ├── 500.html │ │ └── favicon.ico │ └── script │ │ └── rails ├── factories │ ├── redirect_rules.rb │ └── request_environment_rules.rb ├── features │ └── middleware_spec.rb ├── models │ ├── redirect_rule_spec.rb │ └── request_environment_rule_spec.rb └── spec_helper.rb └── tasks └── performance.rake /.coveralls.yml: -------------------------------------------------------------------------------- 1 | service_name: travis-ci 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .bundle/ 2 | log/*.log 3 | pkg/ 4 | spec/dummy/db/*.sqlite3 5 | spec/dummy/log/*.log 6 | spec/dummy/tmp/ 7 | spec/dummy/.sass-cache 8 | .rvmrc 9 | spec/dummy/config/database.yml 10 | .ruby-version 11 | coverage/ 12 | 13 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - "1.9.3" 4 | - "2.0.0" 5 | - "2.1.0" 6 | - "2.1.1" 7 | - "2.1.2" 8 | - "2.1.3" 9 | - "2.1.3" 10 | - "2.1.4" 11 | - "2.1.5" 12 | - "2.1.6" 13 | - "2.2.0" 14 | - "2.2.1" 15 | - "2.2.2" 16 | gemfile: 17 | - gemfiles/rails_31.gemfile 18 | - gemfiles/rails_32.gemfile 19 | - gemfiles/rails_40.gemfile 20 | - gemfiles/rails_41.gemfile 21 | - gemfiles/rails_419.gemfile 22 | - gemfiles/rails_42.gemfile 23 | env: 24 | - DB=mysql 25 | - DB=postgresql 26 | - DB=sqlite 27 | before_install: 28 | - gem update bundler 29 | before_script: 30 | - mysql -e 'create database redirector_dummy_test; create database redirector_dummy_development;' 31 | - psql -c 'create database redirector_dummy_test' -U postgres 32 | - psql -c 'create database redirector_dummy_development' -U postgres 33 | - cp spec/dummy/config/database.travis.yml spec/dummy/config/database.yml 34 | - bundle exec rake db:migrate 35 | matrix: 36 | exclude: 37 | - rvm: 2.2.0 38 | gemfile: gemfiles/rails_31.gemfile 39 | - rvm: 2.2.1 40 | gemfile: gemfiles/rails_31.gemfile 41 | - rvm: 2.2.2 42 | gemfile: gemfiles/rails_31.gemfile 43 | - rvm: 2.2.0 44 | gemfile: gemfiles/rails_32.gemfile 45 | - rvm: 2.2.1 46 | gemfile: gemfiles/rails_32.gemfile 47 | - rvm: 2.2.2 48 | gemfile: gemfiles/rails_32.gemfile 49 | - rvm: 2.2.0 50 | gemfile: gemfiles/rails_40.gemfile 51 | - rvm: 2.2.1 52 | gemfile: gemfiles/rails_40.gemfile 53 | - rvm: 2.2.2 54 | gemfile: gemfiles/rails_40.gemfile 55 | notifications: 56 | slack: viget:g9nhMe2ZIu0p49xgfNQSfWxA 57 | -------------------------------------------------------------------------------- /Appraisals: -------------------------------------------------------------------------------- 1 | appraise "rails-31" do 2 | gem "rails", "~> 3.1.12" 3 | end 4 | 5 | appraise "rails-32" do 6 | gem "rails", "~> 3.2.21" 7 | end 8 | 9 | appraise "rails-40" do 10 | gem "rails", "~> 4.0.13" 11 | end 12 | 13 | appraise "rails-419" do 14 | gem "rails", "4.1.9" 15 | end 16 | 17 | appraise "rails-41" do 18 | gem "rails", "~> 4.1.10" 19 | end 20 | 21 | appraise "rails-42" do 22 | gem "rails", "~> 4.2.1" 23 | end 24 | 25 | appraise "rails-50" do 26 | gem "rails", "~> 5.0.6" 27 | end 28 | 29 | appraise "rails-51" do 30 | gem "rails", "~> 5.1.5" 31 | end 32 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | # Declare your gem's dependencies in redirector.gemspec. 4 | # Bundler will treat runtime dependencies like base dependencies, and 5 | # development dependencies will be added by default to the :development group. 6 | gemspec 7 | 8 | # jquery-rails is used by the dummy application 9 | gem "jquery-rails" 10 | gem 'pry' 11 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | redirector (1.1.4) 5 | rails (>= 3.1) 6 | 7 | GEM 8 | remote: http://rubygems.org/ 9 | specs: 10 | actioncable (5.2.4) 11 | actionpack (= 5.2.4) 12 | nio4r (~> 2.0) 13 | websocket-driver (>= 0.6.1) 14 | actionmailer (5.2.4) 15 | actionpack (= 5.2.4) 16 | actionview (= 5.2.4) 17 | activejob (= 5.2.4) 18 | mail (~> 2.5, >= 2.5.4) 19 | rails-dom-testing (~> 2.0) 20 | actionpack (5.2.4) 21 | actionview (= 5.2.4) 22 | activesupport (= 5.2.4) 23 | rack (~> 2.0) 24 | rack-test (>= 0.6.3) 25 | rails-dom-testing (~> 2.0) 26 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 27 | actionview (5.2.4) 28 | activesupport (= 5.2.4) 29 | builder (~> 3.1) 30 | erubi (~> 1.4) 31 | rails-dom-testing (~> 2.0) 32 | rails-html-sanitizer (~> 1.0, >= 1.0.3) 33 | activejob (5.2.4) 34 | activesupport (= 5.2.4) 35 | globalid (>= 0.3.6) 36 | activemodel (5.2.4) 37 | activesupport (= 5.2.4) 38 | activerecord (5.2.4) 39 | activemodel (= 5.2.4) 40 | activesupport (= 5.2.4) 41 | arel (>= 9.0) 42 | activestorage (5.2.4) 43 | actionpack (= 5.2.4) 44 | activerecord (= 5.2.4) 45 | marcel (~> 0.3.1) 46 | activesupport (5.2.4) 47 | concurrent-ruby (~> 1.0, >= 1.0.2) 48 | i18n (>= 0.7, < 2) 49 | minitest (~> 5.1) 50 | tzinfo (~> 1.1) 51 | addressable (2.5.2) 52 | public_suffix (>= 2.0.2, < 4.0) 53 | appraisal (2.2.0) 54 | bundler 55 | rake 56 | thor (>= 0.14.0) 57 | arel (9.0.0) 58 | builder (3.2.3) 59 | capybara (2.18.0) 60 | addressable 61 | mini_mime (>= 0.1.3) 62 | nokogiri (>= 1.3.3) 63 | rack (>= 1.0.0) 64 | rack-test (>= 0.5.4) 65 | xpath (>= 2.0, < 4.0) 66 | coderay (1.1.2) 67 | concurrent-ruby (1.1.5) 68 | coveralls (0.8.21) 69 | json (>= 1.8, < 3) 70 | simplecov (~> 0.14.1) 71 | term-ansicolor (~> 1.3) 72 | thor (~> 0.19.4) 73 | tins (~> 1.6) 74 | crass (1.0.5) 75 | database_cleaner (1.6.2) 76 | diff-lcs (1.3) 77 | docile (1.1.5) 78 | erubi (1.9.0) 79 | factory_bot (4.8.2) 80 | activesupport (>= 3.0.0) 81 | factory_bot_rails (4.8.2) 82 | factory_bot (~> 4.8.2) 83 | railties (>= 3.0.0) 84 | globalid (0.4.2) 85 | activesupport (>= 4.2.0) 86 | i18n (1.7.0) 87 | concurrent-ruby (~> 1.0) 88 | jquery-rails (4.3.1) 89 | rails-dom-testing (>= 1, < 3) 90 | railties (>= 4.2.0) 91 | thor (>= 0.14, < 2.0) 92 | json (2.1.0) 93 | loofah (2.4.0) 94 | crass (~> 1.0.2) 95 | nokogiri (>= 1.5.9) 96 | mail (2.7.1) 97 | mini_mime (>= 0.1.1) 98 | marcel (0.3.3) 99 | mimemagic (~> 0.3.2) 100 | method_source (0.9.2) 101 | mimemagic (0.3.3) 102 | mini_mime (1.0.2) 103 | mini_portile2 (2.4.0) 104 | minitest (5.13.0) 105 | mysql2 (0.4.10) 106 | nio4r (2.5.2) 107 | nokogiri (1.10.5) 108 | mini_portile2 (~> 2.4.0) 109 | pg (1.0.0) 110 | pry (0.11.3) 111 | coderay (~> 1.1.0) 112 | method_source (~> 0.9.0) 113 | public_suffix (3.0.2) 114 | rack (2.0.7) 115 | rack-test (1.1.0) 116 | rack (>= 1.0, < 3) 117 | rails (5.2.4) 118 | actioncable (= 5.2.4) 119 | actionmailer (= 5.2.4) 120 | actionpack (= 5.2.4) 121 | actionview (= 5.2.4) 122 | activejob (= 5.2.4) 123 | activemodel (= 5.2.4) 124 | activerecord (= 5.2.4) 125 | activestorage (= 5.2.4) 126 | activesupport (= 5.2.4) 127 | bundler (>= 1.3.0) 128 | railties (= 5.2.4) 129 | sprockets-rails (>= 2.0.0) 130 | rails-dom-testing (2.0.3) 131 | activesupport (>= 4.2.0) 132 | nokogiri (>= 1.6) 133 | rails-html-sanitizer (1.3.0) 134 | loofah (~> 2.3) 135 | railties (5.2.4) 136 | actionpack (= 5.2.4) 137 | activesupport (= 5.2.4) 138 | method_source 139 | rake (>= 0.8.7) 140 | thor (>= 0.19.0, < 2.0) 141 | rake (12.3.0) 142 | rspec-core (3.7.1) 143 | rspec-support (~> 3.7.0) 144 | rspec-expectations (3.7.0) 145 | diff-lcs (>= 1.2.0, < 2.0) 146 | rspec-support (~> 3.7.0) 147 | rspec-mocks (3.7.0) 148 | diff-lcs (>= 1.2.0, < 2.0) 149 | rspec-support (~> 3.7.0) 150 | rspec-rails (3.7.2) 151 | actionpack (>= 3.0) 152 | activesupport (>= 3.0) 153 | railties (>= 3.0) 154 | rspec-core (~> 3.7.0) 155 | rspec-expectations (~> 3.7.0) 156 | rspec-mocks (~> 3.7.0) 157 | rspec-support (~> 3.7.0) 158 | rspec-support (3.7.1) 159 | shoulda-matchers (3.1.2) 160 | activesupport (>= 4.0.0) 161 | simplecov (0.14.1) 162 | docile (~> 1.1.0) 163 | json (>= 1.8, < 3) 164 | simplecov-html (~> 0.10.0) 165 | simplecov-html (0.10.2) 166 | sprockets (4.0.0) 167 | concurrent-ruby (~> 1.0) 168 | rack (> 1, < 3) 169 | sprockets-rails (3.2.1) 170 | actionpack (>= 4.0) 171 | activesupport (>= 4.0) 172 | sprockets (>= 3.0.0) 173 | sqlite3 (1.3.13) 174 | term-ansicolor (1.6.0) 175 | tins (~> 1.0) 176 | thor (0.19.4) 177 | thread_safe (0.3.6) 178 | tins (1.16.3) 179 | tzinfo (1.2.5) 180 | thread_safe (~> 0.1) 181 | websocket-driver (0.7.1) 182 | websocket-extensions (>= 0.1.0) 183 | websocket-extensions (0.1.4) 184 | xpath (3.0.0) 185 | nokogiri (~> 1.8) 186 | 187 | PLATFORMS 188 | ruby 189 | 190 | DEPENDENCIES 191 | appraisal 192 | capybara (~> 2.2) 193 | coveralls 194 | database_cleaner 195 | factory_bot_rails (~> 4.4) 196 | jquery-rails 197 | mysql2 198 | pg 199 | pry 200 | rake 201 | redirector! 202 | rspec-rails (~> 3.7) 203 | shoulda-matchers 204 | sqlite3 205 | 206 | BUNDLED WITH 207 | 1.17.2 208 | -------------------------------------------------------------------------------- /HISTORY: -------------------------------------------------------------------------------- 1 | == 0.1.0 / 2012-08-24 2 | * Middleware for redirecting users based on rules stored in the database. 3 | * Rules can have a regex or string source to match against. 4 | * Regex rules can evaluate the destination using groupings from the source. 5 | * Rules can have further request environment conditions to match based on HTTP Headers or Rack environment variables. 6 | * RequestEnvironmentRules can be exact string matches or regex matches. 7 | * Make regex's case sensitivity configurable 8 | 9 | 10 | == 0.1.1 / 2012-08-24 11 | * Destroy RequestEnvironmentRules when the parent RedirectRule is destroyed 12 | * Add some more indexes to redirect_rules table 13 | * Allow query strings to be part of the match on RedirectRules 14 | 15 | == 0.1.2 / 2012-08-27 16 | * Change ordering on match to prefer exact matches and longer matches 17 | 18 | == 0.1.3 / 2012-08-28 19 | * Include request_environment_rules when pulling back possible matches 20 | 21 | == 0.1.4 / 2012-09-07 22 | * Allow nested attributes for request environment rules on redirect rules and be set by mass assignment. 23 | * [BUG] Allow active to be set to false 24 | * [BUG] Handle a nil value for a match group correctly 25 | 26 | == 0.1.5 / 2014-01-16 27 | * Officially support Rails 4 28 | * Add `silence_sql_logs` config option 29 | * Handle ports on redirects properly 30 | * Better handle `URI::InvalidURIError` exceptions inside middleware by raising custom error 31 | * Minor bug fix 32 | 33 | == 1.0.0 / 2014-03-07 34 | * Add `preserve_query` option to preserve the query string from source to destination URL 35 | 36 | == 1.0.1 / 2014-09-26 37 | * Fix case sensitive/insensitive matching for non-regex rules 38 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Brian Landau 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Redirector 2 | 3 | [![Code Climate](https://codeclimate.com/github/vigetlabs/redirector.png)](https://codeclimate.com/github/vigetlabs/redirector) [![Build Status](https://travis-ci.org/vigetlabs/redirector.png?branch=master)](https://travis-ci.org/vigetlabs/redirector) [![Coverage Status](https://coveralls.io/repos/vigetlabs/redirector/badge.png?branch=master)](https://coveralls.io/r/vigetlabs/redirector?branch=master) [![Gem Version](https://badge.fury.io/rb/redirector.png)](http://badge.fury.io/rb/redirector) 4 | 5 | 6 | Redirector is a Rails engine that adds a piece of middleware to the top of your middleware stack that looks for redirect rules stored in your database and redirects you accordingly. 7 | 8 | ## Install 9 | 10 | 1. Add this to your Gemfile and then `bundle install`: 11 | 12 | ```ruby 13 | gem 'redirector' 14 | ``` 15 | 16 | 2. `$ rake redirector_engine:install:migrations` 17 | 3. `$ rake db:migrate` 18 | 4. Create an interface for admins to manage the redirect rules. 19 | 20 | 21 | ### Config options 22 | 23 | `include_query_in_source`: If you want your redirect rules to also match against the query string as well as the path then you need to set this to `true` (the default is `false`). 24 | 25 | `silence_sql_logs`: This option silences the logging of Redirector related SQL queries in your log file. 26 | 27 | `preserve_query`: Pass the query string parameters through from the source to the target URL. 28 | 29 | `ignored_patterns`: Lets you define an array of regex patterns which will be ignored when searching for redirect records. ie: `[/^\/assets\/.+/]` will bypass a database lookup for any path that starts with `/assets/`. This can be useful in preventing numerous unnecessary lookups. 30 | 31 | You can set these inside your configuration in `config/application.rb` of your Rails application like so: 32 | 33 | ```ruby 34 | module MyApplication 35 | class Application < Rails::Application 36 | # ... 37 | 38 | config.redirector.include_query_in_source = true 39 | config.redirector.silence_sql_logs = true 40 | config.redirector.ignored_patterns = [/^\/assets\/.+/] 41 | end 42 | end 43 | ``` 44 | 45 | ## Redirect Rule definitions 46 | 47 | Redirect rules have 3 parts: 48 | 49 | 1. A Source 50 | 2. A Destination 51 | 3. Request environment conditions 52 | 53 | The source defines how to match the incoming request path and the destination is where to send the visitor if the match is made. A source can be a strict string equality match or it can be a regular expression that is matched. If a regular expression is used and it uses groupings, you can reference those groupings inside of the destination. For instance a regex like `/my_custom_path\/([0-9]+)/` could use that grouping in the destination like this `"/my_destination/$1"`. So, if the request path was `"/my_custom_path/10"` then the destination for that rule would be `"/my_destination/10"`. 54 | 55 | Redirect rules can also have further Rack/HTTP environment (mainly HTTP headers) conditions via RequestEnvironmentRules. These define a key in the rack environment passed into the middleware and a value match you require for the redirect rule it's tied too. Similar to the redirect rules these RequestEnvironmentRules can be string matches or regex matches. A redirect rule can have as many of these environment rules as you need. 56 | 57 | When using regex matching on either a redirect rule source or a request environment rule environment value you can specify if you want the matching to be case sensitive or case insensitive with a boolean column that's on the table. 58 | 59 | ### Schema Definition 60 | 61 | Here's the schema definition used for the two tables: 62 | 63 | ```ruby 64 | create_table "redirect_rules", :force => true do |t| 65 | t.string "source", :null => false # Matched against the request path 66 | t.boolean "source_is_regex", :default => false, :null => false # Is the source a regular expression or not 67 | t.boolean "source_is_case_sensitive", :default => false, :null => false # Is the source regex cas sensitive or not 68 | t.string "destination", :null => false 69 | t.boolean "active", :default => false # Should this rule be applied or not 70 | t.datetime "created_at", :null => false 71 | t.datetime "updated_at", :null => false 72 | end 73 | 74 | create_table "request_environment_rules", :force => true do |t| 75 | t.integer "redirect_rule_id", :null => false 76 | t.string "environment_key_name", :null => false # Name of the enviornment key (e.g. "QUERY_STRING", "HTTP_HOST") 77 | t.string "environment_value", :null => false # What to match the value of the specified environment attribute against 78 | t.boolean "environment_value_is_regex", :default => false, :null => false # Is the value match a regex or not 79 | t.boolean "environment_value_is_case_sensitive", :default => true, :null => false # is the value regex case sensitive or not 80 | t.datetime "created_at", :null => false 81 | t.datetime "updated_at", :null => false 82 | end 83 | ``` 84 | 85 | ## Databases supported 86 | 87 | * MySQL 88 | * PostgreSQL 89 | 90 | If you require support for another database, the only thing that needs to be added is a definition for a SQL regular expression conditional (see `app/models/redirect_rule.rb`). If you create a pull request that adds support for another database, it will most likely be merged in. 91 | 92 | ## Contributing to Redirector 93 | 94 | * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet. 95 | * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it. 96 | * Fork the project. 97 | * Start a feature/bugfix branch. 98 | * Commit and push until you are happy with your contribution. 99 | * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally. 100 | * We're using [Appraisal](https://github.com/thoughtbot/appraisal) to test against different Rails versions. 101 | * In order to run the tests you'll need to do the following: 102 | 1. `cp spec/dummy/config/database.yml.example spec/dummy/config/database.yml` 103 | 2. modify that `spec/dummy/config/database.yml` with your mysql configuration details 104 | 3. run `appraisal install` (should only need to do this once) 105 | 4. run `appraisal rake spec` 106 | * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it. 107 | 108 | ## Copyright 109 | 110 | Copyright (c) 2012 Brian Landau (Viget). See MIT_LICENSE for further details. 111 | 112 | *** 113 | 114 | 115 | Code At Viget 116 | 117 | 118 | Visit [code.viget.com](http://code.viget.com) to see more projects from [Viget.](https://viget.com) 119 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | begin 3 | require 'bundler/setup' 4 | require 'appraisal' 5 | rescue LoadError 6 | puts 'You must `gem install bundler` and `bundle install` to run rake tasks' 7 | end 8 | 9 | APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__) 10 | load 'rails/tasks/engine.rake' 11 | 12 | Bundler::GemHelper.install_tasks 13 | 14 | Dir[File.join(File.dirname(__FILE__), 'tasks/**/*.rake')].each {|f| load f } 15 | 16 | require 'rspec/core' 17 | require 'rspec/core/rake_task' 18 | 19 | desc "Run all specs in spec directory (excluding plugin specs)" 20 | RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare') 21 | 22 | task :default => :spec 23 | -------------------------------------------------------------------------------- /app/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vigetlabs/redirector/e3add13562df57b4c9591c138dacbb8c30b582b0/app/models/.gitkeep -------------------------------------------------------------------------------- /app/models/redirect_rule.rb: -------------------------------------------------------------------------------- 1 | class RedirectRule < ActiveRecord::Base 2 | extend Redirector::RegexAttribute 3 | regex_attribute :source 4 | 5 | has_many :request_environment_rules, :inverse_of => :redirect_rule, :dependent => :destroy 6 | 7 | attr_accessible :source, 8 | :source_is_regex, 9 | :destination, 10 | :active, 11 | :source_is_case_sensitive, 12 | :request_environment_rules_attributes if Redirector.active_record_protected_attributes? 13 | 14 | accepts_nested_attributes_for :request_environment_rules, :allow_destroy => true, :reject_if => :all_blank 15 | 16 | validates :source, :destination, :presence => true 17 | 18 | # Not working with rails 5.0.1 19 | if Rails.version.to_i < 5 20 | validates :active, :inclusion => { :in => ['0', '1', true, false] } 21 | end 22 | 23 | before_save :strip_source_whitespace, :strip_destination_whitespace 24 | 25 | def self.regex_expression 26 | if connection_mysql? 27 | '(redirect_rules.source_is_case_sensitive = :true AND CAST(:source AS BINARY) REGEXP BINARY redirect_rules.source) OR '+ 28 | '(redirect_rules.source_is_case_sensitive = :false AND :source REGEXP redirect_rules.source)' 29 | elsif connection_sqlite? 30 | '(redirect_rules.source_is_case_sensitive = :true AND :source REGEXP redirect_rules.source COLLATE BINARY) OR '+ 31 | '(redirect_rules.source_is_case_sensitive = :false AND :source REGEXP redirect_rules.source)' 32 | else 33 | '(redirect_rules.source_is_case_sensitive = :true AND :source ~ redirect_rules.source) OR '+ 34 | '(redirect_rules.source_is_case_sensitive = :false AND :source ~* redirect_rules.source)' 35 | end 36 | end 37 | 38 | def self.match_sql_condition 39 | <<-SQL 40 | redirect_rules.active = :true AND 41 | ((source_is_regex = :false AND source_is_case_sensitive = :false AND LOWER(redirect_rules.source) = LOWER(:source)) OR 42 | (source_is_regex = :false AND source_is_case_sensitive = :true AND #{'BINARY' if connection_mysql?} redirect_rules.source = :source #{'COLLATE BINARY' if connection_sqlite?}) OR 43 | (source_is_regex = :true AND (#{regex_expression}))) 44 | SQL 45 | end 46 | 47 | def self.match_for(source, environment) 48 | match_scope = where(match_sql_condition.strip, {:true => true, :false => false, :source => source}) 49 | match_scope = match_scope.order(Arel.sql('redirect_rules.source_is_regex ASC, LENGTH(redirect_rules.source) DESC')) 50 | match_scope = match_scope.includes(:request_environment_rules) 51 | match_scope = match_scope.references(:request_environment_rules) if Rails.version.to_i == 4 52 | match_scope.detect do |rule| 53 | rule.request_environment_rules.all? {|env_rule| env_rule.matches?(environment) } 54 | end 55 | end 56 | 57 | def self.destination_for(source, environment) 58 | rule = match_for(source, environment) 59 | rule.evaluated_destination_for(source) if rule 60 | end 61 | 62 | def evaluated_destination_for(request_path) 63 | if source_is_regex? && request_path =~ source_regex 64 | matches = $~ 65 | number_of_grouped_matches = matches.length - 1 66 | final_destination = destination.dup 67 | 68 | number_of_grouped_matches.downto(1) do |index| 69 | final_destination.gsub!(/\$#{index}/, matches[index].to_s) 70 | end 71 | 72 | final_destination 73 | else 74 | destination 75 | end 76 | end 77 | 78 | private 79 | 80 | def self.connection_mysql? 81 | connection.adapter_name.downcase.include?('mysql') 82 | end 83 | 84 | def self.connection_sqlite? 85 | connection.adapter_name.downcase.include?('sqlite') 86 | end 87 | 88 | def strip_source_whitespace 89 | self.source = self.source.strip 90 | end 91 | 92 | def strip_destination_whitespace 93 | self.destination = self.destination.strip 94 | end 95 | 96 | end 97 | -------------------------------------------------------------------------------- /app/models/request_environment_rule.rb: -------------------------------------------------------------------------------- 1 | class RequestEnvironmentRule < ActiveRecord::Base 2 | extend Redirector::RegexAttribute 3 | regex_attribute :environment_value 4 | 5 | belongs_to :redirect_rule 6 | 7 | attr_accessible :redirect_rule_id, 8 | :environment_key_name, 9 | :environment_value, 10 | :environment_value_is_regex, 11 | :environment_value_is_case_sensitive if Redirector.active_record_protected_attributes? 12 | 13 | validates :redirect_rule, :environment_key_name, :environment_value, :presence => true 14 | 15 | def matches?(environment) 16 | if environment_value_is_regex? 17 | environment[environment_key_name] && environment[environment_key_name] =~ environment_value_regex 18 | else 19 | environment[environment_key_name] == environment_value 20 | end 21 | end 22 | 23 | end 24 | -------------------------------------------------------------------------------- /db/migrate/20120815212612_create_redirect_rules.rb: -------------------------------------------------------------------------------- 1 | class CreateRedirectRules < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :redirect_rules do |t| 4 | t.string :source, :null => false 5 | t.boolean :source_is_regex, :null => false, :default => false 6 | t.boolean :source_is_case_sensitive, :null => false, :default => false 7 | t.string :destination, :null => false 8 | t.boolean :active, :default => false 9 | t.timestamps 10 | end 11 | add_index :redirect_rules, :source 12 | add_index :redirect_rules, :active 13 | add_index :redirect_rules, :source_is_regex 14 | add_index :redirect_rules, :source_is_case_sensitive 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /db/migrate/20120823163756_create_request_environment_rules.rb: -------------------------------------------------------------------------------- 1 | class CreateRequestEnvironmentRules < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :request_environment_rules do |t| 4 | t.integer :redirect_rule_id, :null => false 5 | t.string :environment_key_name, :null => false 6 | t.string :environment_value, :null => false 7 | t.boolean :environment_value_is_regex, :null => false, :default => false 8 | t.boolean :environment_value_is_case_sensitive, :null => false, :default => true 9 | t.timestamps 10 | end 11 | add_index :request_environment_rules, :redirect_rule_id 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /gemfiles/rails_31.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "http://rubygems.org" 4 | 5 | gem "jquery-rails" 6 | gem "pry" 7 | gem "rails", "~> 3.1.12" 8 | 9 | gemspec path: "../" 10 | -------------------------------------------------------------------------------- /gemfiles/rails_31.gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: .. 3 | specs: 4 | redirector (1.1.2) 5 | rails (>= 3.1) 6 | 7 | GEM 8 | remote: http://rubygems.org/ 9 | specs: 10 | actionmailer (3.1.12) 11 | actionpack (= 3.1.12) 12 | mail (~> 2.4.4) 13 | actionpack (3.1.12) 14 | activemodel (= 3.1.12) 15 | activesupport (= 3.1.12) 16 | builder (~> 3.0.0) 17 | erubis (~> 2.7.0) 18 | i18n (~> 0.6) 19 | rack (~> 1.3.6) 20 | rack-cache (~> 1.2) 21 | rack-mount (~> 0.8.2) 22 | rack-test (~> 0.6.1) 23 | sprockets (~> 2.0.4) 24 | activemodel (3.1.12) 25 | activesupport (= 3.1.12) 26 | builder (~> 3.0.0) 27 | i18n (~> 0.6) 28 | activerecord (3.1.12) 29 | activemodel (= 3.1.12) 30 | activesupport (= 3.1.12) 31 | arel (~> 2.2.3) 32 | tzinfo (~> 0.3.29) 33 | activeresource (3.1.12) 34 | activemodel (= 3.1.12) 35 | activesupport (= 3.1.12) 36 | activesupport (3.1.12) 37 | multi_json (~> 1.0) 38 | appraisal (1.0.3) 39 | bundler 40 | rake 41 | thor (>= 0.14.0) 42 | arel (2.2.3) 43 | builder (3.0.4) 44 | capybara (2.4.4) 45 | mime-types (>= 1.16) 46 | nokogiri (>= 1.3.3) 47 | rack (>= 1.0.0) 48 | rack-test (>= 0.5.4) 49 | xpath (~> 2.0) 50 | coderay (1.1.2) 51 | coveralls (0.7.1) 52 | multi_json (~> 1.3) 53 | rest-client 54 | simplecov (>= 0.7) 55 | term-ansicolor 56 | thor 57 | database_cleaner (1.4.1) 58 | diff-lcs (1.3) 59 | docile (1.1.5) 60 | domain_name (0.5.24) 61 | unf (>= 0.0.5, < 1.0.0) 62 | erubis (2.7.0) 63 | factory_bot (4.10.0) 64 | activesupport (>= 3.0.0) 65 | factory_bot_rails (4.10.0) 66 | factory_bot (~> 4.10.0) 67 | railties (>= 3.0.0) 68 | hike (1.2.3) 69 | http-cookie (1.0.2) 70 | domain_name (~> 0.5) 71 | i18n (0.7.0) 72 | jquery-rails (3.1.2) 73 | railties (>= 3.0, < 5.0) 74 | thor (>= 0.14, < 2.0) 75 | json (1.8.6) 76 | mail (2.4.4) 77 | i18n (>= 0.4.0) 78 | mime-types (~> 1.16) 79 | treetop (~> 1.4.8) 80 | method_source (0.9.0) 81 | mime-types (1.25.1) 82 | mini_portile (0.6.2) 83 | multi_json (1.11.0) 84 | mysql2 (0.3.18) 85 | netrc (0.10.3) 86 | nokogiri (1.6.6.2) 87 | mini_portile (~> 0.6.0) 88 | pg (0.18.1) 89 | polyglot (0.3.5) 90 | pry (0.11.3) 91 | coderay (~> 1.1.0) 92 | method_source (~> 0.9.0) 93 | rack (1.3.10) 94 | rack-cache (1.2) 95 | rack (>= 0.4) 96 | rack-mount (0.8.3) 97 | rack (>= 1.0.0) 98 | rack-ssl (1.3.4) 99 | rack 100 | rack-test (0.6.3) 101 | rack (>= 1.0) 102 | rails (3.1.12) 103 | actionmailer (= 3.1.12) 104 | actionpack (= 3.1.12) 105 | activerecord (= 3.1.12) 106 | activeresource (= 3.1.12) 107 | activesupport (= 3.1.12) 108 | bundler (~> 1.0) 109 | railties (= 3.1.12) 110 | railties (3.1.12) 111 | actionpack (= 3.1.12) 112 | activesupport (= 3.1.12) 113 | rack-ssl (~> 1.3.2) 114 | rake (>= 0.8.7) 115 | rdoc (~> 3.4) 116 | thor (~> 0.14.6) 117 | rake (10.4.2) 118 | rdoc (3.12.2) 119 | json (~> 1.4) 120 | rest-client (1.8.0) 121 | http-cookie (>= 1.0.2, < 2.0) 122 | mime-types (>= 1.16, < 3.0) 123 | netrc (~> 0.7) 124 | rspec-core (3.8.0) 125 | rspec-support (~> 3.8.0) 126 | rspec-expectations (3.8.1) 127 | diff-lcs (>= 1.2.0, < 2.0) 128 | rspec-support (~> 3.8.0) 129 | rspec-mocks (3.8.0) 130 | diff-lcs (>= 1.2.0, < 2.0) 131 | rspec-support (~> 3.8.0) 132 | rspec-rails (3.8.0) 133 | actionpack (>= 3.0) 134 | activesupport (>= 3.0) 135 | railties (>= 3.0) 136 | rspec-core (~> 3.8.0) 137 | rspec-expectations (~> 3.8.0) 138 | rspec-mocks (~> 3.8.0) 139 | rspec-support (~> 3.8.0) 140 | rspec-support (3.8.0) 141 | shoulda-matchers (2.8.0) 142 | activesupport (>= 3.0.0) 143 | simplecov (0.10.0) 144 | docile (~> 1.1.0) 145 | json (~> 1.8) 146 | simplecov-html (~> 0.10.0) 147 | simplecov-html (0.10.0) 148 | sprockets (2.0.5) 149 | hike (~> 1.2) 150 | rack (~> 1.0) 151 | tilt (~> 1.1, != 1.3.0) 152 | sqlite3 (1.3.13) 153 | term-ansicolor (1.3.0) 154 | tins (~> 1.0) 155 | thor (0.14.6) 156 | tilt (1.4.1) 157 | tins (1.3.5) 158 | treetop (1.4.15) 159 | polyglot 160 | polyglot (>= 0.3.1) 161 | tzinfo (0.3.43) 162 | unf (0.1.4) 163 | unf_ext 164 | unf_ext (0.0.7.1) 165 | xpath (2.0.0) 166 | nokogiri (~> 1.3) 167 | 168 | PLATFORMS 169 | ruby 170 | 171 | DEPENDENCIES 172 | appraisal 173 | capybara (~> 2.2) 174 | coveralls 175 | database_cleaner 176 | factory_bot_rails (~> 4.4) 177 | jquery-rails 178 | mysql2 179 | pg 180 | pry 181 | rails (~> 3.1.12) 182 | rake 183 | redirector! 184 | rspec-rails (~> 3.7) 185 | shoulda-matchers 186 | sqlite3 187 | 188 | BUNDLED WITH 189 | 1.16.1 190 | -------------------------------------------------------------------------------- /gemfiles/rails_32.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "http://rubygems.org" 4 | 5 | gem "jquery-rails" 6 | gem "pry" 7 | gem "rails", "~> 3.2.21" 8 | 9 | gemspec path: "../" 10 | -------------------------------------------------------------------------------- /gemfiles/rails_32.gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: .. 3 | specs: 4 | redirector (1.1.2) 5 | rails (>= 3.1) 6 | 7 | GEM 8 | remote: http://rubygems.org/ 9 | specs: 10 | actionmailer (3.2.21) 11 | actionpack (= 3.2.21) 12 | mail (~> 2.5.4) 13 | actionpack (3.2.21) 14 | activemodel (= 3.2.21) 15 | activesupport (= 3.2.21) 16 | builder (~> 3.0.0) 17 | erubis (~> 2.7.0) 18 | journey (~> 1.0.4) 19 | rack (~> 1.4.5) 20 | rack-cache (~> 1.2) 21 | rack-test (~> 0.6.1) 22 | sprockets (~> 2.2.1) 23 | activemodel (3.2.21) 24 | activesupport (= 3.2.21) 25 | builder (~> 3.0.0) 26 | activerecord (3.2.21) 27 | activemodel (= 3.2.21) 28 | activesupport (= 3.2.21) 29 | arel (~> 3.0.2) 30 | tzinfo (~> 0.3.29) 31 | activeresource (3.2.21) 32 | activemodel (= 3.2.21) 33 | activesupport (= 3.2.21) 34 | activesupport (3.2.21) 35 | i18n (~> 0.6, >= 0.6.4) 36 | multi_json (~> 1.0) 37 | appraisal (2.0.1) 38 | activesupport (>= 3.2.21) 39 | bundler 40 | rake 41 | thor (>= 0.14.0) 42 | arel (3.0.3) 43 | builder (3.0.4) 44 | capybara (2.4.4) 45 | mime-types (>= 1.16) 46 | nokogiri (>= 1.3.3) 47 | rack (>= 1.0.0) 48 | rack-test (>= 0.5.4) 49 | xpath (~> 2.0) 50 | coderay (1.1.2) 51 | coveralls (0.8.1) 52 | json (~> 1.8) 53 | rest-client (>= 1.6.8, < 2) 54 | simplecov (~> 0.10.0) 55 | term-ansicolor (~> 1.3) 56 | thor (~> 0.19.1) 57 | database_cleaner (1.4.1) 58 | diff-lcs (1.3) 59 | docile (1.1.5) 60 | domain_name (0.5.24) 61 | unf (>= 0.0.5, < 1.0.0) 62 | erubis (2.7.0) 63 | factory_bot (4.10.0) 64 | activesupport (>= 3.0.0) 65 | factory_bot_rails (4.10.0) 66 | factory_bot (~> 4.10.0) 67 | railties (>= 3.0.0) 68 | hike (1.2.3) 69 | http-cookie (1.0.2) 70 | domain_name (~> 0.5) 71 | i18n (0.7.0) 72 | journey (1.0.4) 73 | jquery-rails (3.1.2) 74 | railties (>= 3.0, < 5.0) 75 | thor (>= 0.14, < 2.0) 76 | json (1.8.6) 77 | mail (2.5.4) 78 | mime-types (~> 1.16) 79 | treetop (~> 1.4.8) 80 | method_source (0.9.0) 81 | mime-types (1.25.1) 82 | mini_portile (0.6.2) 83 | multi_json (1.11.0) 84 | mysql2 (0.3.18) 85 | netrc (0.10.3) 86 | nokogiri (1.6.6.2) 87 | mini_portile (~> 0.6.0) 88 | pg (0.18.1) 89 | polyglot (0.3.5) 90 | pry (0.11.3) 91 | coderay (~> 1.1.0) 92 | method_source (~> 0.9.0) 93 | rack (1.4.5) 94 | rack-cache (1.2) 95 | rack (>= 0.4) 96 | rack-ssl (1.3.4) 97 | rack 98 | rack-test (0.6.3) 99 | rack (>= 1.0) 100 | rails (3.2.21) 101 | actionmailer (= 3.2.21) 102 | actionpack (= 3.2.21) 103 | activerecord (= 3.2.21) 104 | activeresource (= 3.2.21) 105 | activesupport (= 3.2.21) 106 | bundler (~> 1.0) 107 | railties (= 3.2.21) 108 | railties (3.2.21) 109 | actionpack (= 3.2.21) 110 | activesupport (= 3.2.21) 111 | rack-ssl (~> 1.3.2) 112 | rake (>= 0.8.7) 113 | rdoc (~> 3.4) 114 | thor (>= 0.14.6, < 2.0) 115 | rake (10.4.2) 116 | rdoc (3.12.2) 117 | json (~> 1.4) 118 | rest-client (1.8.0) 119 | http-cookie (>= 1.0.2, < 2.0) 120 | mime-types (>= 1.16, < 3.0) 121 | netrc (~> 0.7) 122 | rspec-core (3.8.0) 123 | rspec-support (~> 3.8.0) 124 | rspec-expectations (3.8.1) 125 | diff-lcs (>= 1.2.0, < 2.0) 126 | rspec-support (~> 3.8.0) 127 | rspec-mocks (3.8.0) 128 | diff-lcs (>= 1.2.0, < 2.0) 129 | rspec-support (~> 3.8.0) 130 | rspec-rails (3.8.0) 131 | actionpack (>= 3.0) 132 | activesupport (>= 3.0) 133 | railties (>= 3.0) 134 | rspec-core (~> 3.8.0) 135 | rspec-expectations (~> 3.8.0) 136 | rspec-mocks (~> 3.8.0) 137 | rspec-support (~> 3.8.0) 138 | rspec-support (3.8.0) 139 | shoulda-matchers (2.8.0) 140 | activesupport (>= 3.0.0) 141 | simplecov (0.10.0) 142 | docile (~> 1.1.0) 143 | json (~> 1.8) 144 | simplecov-html (~> 0.10.0) 145 | simplecov-html (0.10.0) 146 | sprockets (2.2.3) 147 | hike (~> 1.2) 148 | multi_json (~> 1.0) 149 | rack (~> 1.0) 150 | tilt (~> 1.1, != 1.3.0) 151 | sqlite3 (1.3.13) 152 | term-ansicolor (1.3.0) 153 | tins (~> 1.0) 154 | thor (0.19.1) 155 | tilt (1.4.1) 156 | tins (1.3.5) 157 | treetop (1.4.15) 158 | polyglot 159 | polyglot (>= 0.3.1) 160 | tzinfo (0.3.43) 161 | unf (0.1.4) 162 | unf_ext 163 | unf_ext (0.0.7.1) 164 | xpath (2.0.0) 165 | nokogiri (~> 1.3) 166 | 167 | PLATFORMS 168 | ruby 169 | 170 | DEPENDENCIES 171 | appraisal 172 | capybara (~> 2.2) 173 | coveralls 174 | database_cleaner 175 | factory_bot_rails (~> 4.4) 176 | jquery-rails 177 | mysql2 178 | pg 179 | pry 180 | rails (~> 3.2.21) 181 | rake 182 | redirector! 183 | rspec-rails (~> 3.7) 184 | shoulda-matchers 185 | sqlite3 186 | 187 | BUNDLED WITH 188 | 1.16.1 189 | -------------------------------------------------------------------------------- /gemfiles/rails_40.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "http://rubygems.org" 4 | 5 | gem "jquery-rails" 6 | gem "pry" 7 | gem "rails", "~> 4.0.13" 8 | 9 | gemspec path: "../" 10 | -------------------------------------------------------------------------------- /gemfiles/rails_40.gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: .. 3 | specs: 4 | redirector (1.1.2) 5 | rails (>= 3.1) 6 | 7 | GEM 8 | remote: http://rubygems.org/ 9 | specs: 10 | actionmailer (4.0.13) 11 | actionpack (= 4.0.13) 12 | mail (~> 2.5, >= 2.5.4) 13 | actionpack (4.0.13) 14 | activesupport (= 4.0.13) 15 | builder (~> 3.1.0) 16 | erubis (~> 2.7.0) 17 | rack (~> 1.5.2) 18 | rack-test (~> 0.6.2) 19 | activemodel (4.0.13) 20 | activesupport (= 4.0.13) 21 | builder (~> 3.1.0) 22 | activerecord (4.0.13) 23 | activemodel (= 4.0.13) 24 | activerecord-deprecated_finders (~> 1.0.2) 25 | activesupport (= 4.0.13) 26 | arel (~> 4.0.0) 27 | activerecord-deprecated_finders (1.0.4) 28 | activesupport (4.0.13) 29 | i18n (~> 0.6, >= 0.6.9) 30 | minitest (~> 4.2) 31 | multi_json (~> 1.3) 32 | thread_safe (~> 0.1) 33 | tzinfo (~> 0.3.37) 34 | appraisal (2.0.1) 35 | activesupport (>= 3.2.21) 36 | bundler 37 | rake 38 | thor (>= 0.14.0) 39 | arel (4.0.2) 40 | builder (3.1.4) 41 | capybara (2.4.4) 42 | mime-types (>= 1.16) 43 | nokogiri (>= 1.3.3) 44 | rack (>= 1.0.0) 45 | rack-test (>= 0.5.4) 46 | xpath (~> 2.0) 47 | coderay (1.1.2) 48 | coveralls (0.8.1) 49 | json (~> 1.8) 50 | rest-client (>= 1.6.8, < 2) 51 | simplecov (~> 0.10.0) 52 | term-ansicolor (~> 1.3) 53 | thor (~> 0.19.1) 54 | database_cleaner (1.4.1) 55 | diff-lcs (1.3) 56 | docile (1.1.5) 57 | domain_name (0.5.24) 58 | unf (>= 0.0.5, < 1.0.0) 59 | erubis (2.7.0) 60 | factory_bot (4.10.0) 61 | activesupport (>= 3.0.0) 62 | factory_bot_rails (4.10.0) 63 | factory_bot (~> 4.10.0) 64 | railties (>= 3.0.0) 65 | http-cookie (1.0.2) 66 | domain_name (~> 0.5) 67 | i18n (0.7.0) 68 | jquery-rails (3.1.2) 69 | railties (>= 3.0, < 5.0) 70 | thor (>= 0.14, < 2.0) 71 | json (1.8.6) 72 | mail (2.6.3) 73 | mime-types (>= 1.16, < 3) 74 | method_source (0.9.0) 75 | mime-types (2.4.3) 76 | mini_portile (0.6.2) 77 | minitest (4.7.5) 78 | multi_json (1.11.0) 79 | mysql2 (0.3.18) 80 | netrc (0.10.3) 81 | nokogiri (1.6.6.2) 82 | mini_portile (~> 0.6.0) 83 | pg (0.18.1) 84 | pry (0.11.3) 85 | coderay (~> 1.1.0) 86 | method_source (~> 0.9.0) 87 | rack (1.5.2) 88 | rack-test (0.6.3) 89 | rack (>= 1.0) 90 | rails (4.0.13) 91 | actionmailer (= 4.0.13) 92 | actionpack (= 4.0.13) 93 | activerecord (= 4.0.13) 94 | activesupport (= 4.0.13) 95 | bundler (>= 1.3.0, < 2.0) 96 | railties (= 4.0.13) 97 | sprockets-rails (~> 2.0) 98 | railties (4.0.13) 99 | actionpack (= 4.0.13) 100 | activesupport (= 4.0.13) 101 | rake (>= 0.8.7) 102 | thor (>= 0.18.1, < 2.0) 103 | rake (10.4.2) 104 | rest-client (1.8.0) 105 | http-cookie (>= 1.0.2, < 2.0) 106 | mime-types (>= 1.16, < 3.0) 107 | netrc (~> 0.7) 108 | rspec-core (3.8.0) 109 | rspec-support (~> 3.8.0) 110 | rspec-expectations (3.8.1) 111 | diff-lcs (>= 1.2.0, < 2.0) 112 | rspec-support (~> 3.8.0) 113 | rspec-mocks (3.8.0) 114 | diff-lcs (>= 1.2.0, < 2.0) 115 | rspec-support (~> 3.8.0) 116 | rspec-rails (3.8.0) 117 | actionpack (>= 3.0) 118 | activesupport (>= 3.0) 119 | railties (>= 3.0) 120 | rspec-core (~> 3.8.0) 121 | rspec-expectations (~> 3.8.0) 122 | rspec-mocks (~> 3.8.0) 123 | rspec-support (~> 3.8.0) 124 | rspec-support (3.8.0) 125 | shoulda-matchers (2.8.0) 126 | activesupport (>= 3.0.0) 127 | simplecov (0.10.0) 128 | docile (~> 1.1.0) 129 | json (~> 1.8) 130 | simplecov-html (~> 0.10.0) 131 | simplecov-html (0.10.0) 132 | sprockets (3.0.1) 133 | rack (~> 1.0) 134 | sprockets-rails (2.2.4) 135 | actionpack (>= 3.0) 136 | activesupport (>= 3.0) 137 | sprockets (>= 2.8, < 4.0) 138 | sqlite3 (1.3.13) 139 | term-ansicolor (1.3.0) 140 | tins (~> 1.0) 141 | thor (0.19.1) 142 | thread_safe (0.3.5) 143 | tins (1.3.5) 144 | tzinfo (0.3.43) 145 | unf (0.1.4) 146 | unf_ext 147 | unf_ext (0.0.7.1) 148 | xpath (2.0.0) 149 | nokogiri (~> 1.3) 150 | 151 | PLATFORMS 152 | ruby 153 | 154 | DEPENDENCIES 155 | appraisal 156 | capybara (~> 2.2) 157 | coveralls 158 | database_cleaner 159 | factory_bot_rails (~> 4.4) 160 | jquery-rails 161 | mysql2 162 | pg 163 | pry 164 | rails (~> 4.0.13) 165 | rake 166 | redirector! 167 | rspec-rails (~> 3.7) 168 | shoulda-matchers 169 | sqlite3 170 | 171 | BUNDLED WITH 172 | 1.16.1 173 | -------------------------------------------------------------------------------- /gemfiles/rails_41.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "http://rubygems.org" 4 | 5 | gem "jquery-rails" 6 | gem "pry" 7 | gem "rails", "~> 4.1.10" 8 | 9 | gemspec path: "../" 10 | -------------------------------------------------------------------------------- /gemfiles/rails_41.gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: .. 3 | specs: 4 | redirector (1.1.2) 5 | rails (>= 3.1) 6 | 7 | GEM 8 | remote: http://rubygems.org/ 9 | specs: 10 | actionmailer (4.1.10) 11 | actionpack (= 4.1.10) 12 | actionview (= 4.1.10) 13 | mail (~> 2.5, >= 2.5.4) 14 | actionpack (4.1.10) 15 | actionview (= 4.1.10) 16 | activesupport (= 4.1.10) 17 | rack (~> 1.5.2) 18 | rack-test (~> 0.6.2) 19 | actionview (4.1.10) 20 | activesupport (= 4.1.10) 21 | builder (~> 3.1) 22 | erubis (~> 2.7.0) 23 | activemodel (4.1.10) 24 | activesupport (= 4.1.10) 25 | builder (~> 3.1) 26 | activerecord (4.1.10) 27 | activemodel (= 4.1.10) 28 | activesupport (= 4.1.10) 29 | arel (~> 5.0.0) 30 | activesupport (4.1.10) 31 | i18n (~> 0.6, >= 0.6.9) 32 | json (~> 1.7, >= 1.7.7) 33 | minitest (~> 5.1) 34 | thread_safe (~> 0.1) 35 | tzinfo (~> 1.1) 36 | appraisal (2.0.1) 37 | activesupport (>= 3.2.21) 38 | bundler 39 | rake 40 | thor (>= 0.14.0) 41 | arel (5.0.1.20140414130214) 42 | builder (3.2.2) 43 | capybara (2.4.4) 44 | mime-types (>= 1.16) 45 | nokogiri (>= 1.3.3) 46 | rack (>= 1.0.0) 47 | rack-test (>= 0.5.4) 48 | xpath (~> 2.0) 49 | coderay (1.1.2) 50 | coveralls (0.8.1) 51 | json (~> 1.8) 52 | rest-client (>= 1.6.8, < 2) 53 | simplecov (~> 0.10.0) 54 | term-ansicolor (~> 1.3) 55 | thor (~> 0.19.1) 56 | database_cleaner (1.4.1) 57 | diff-lcs (1.3) 58 | docile (1.1.5) 59 | domain_name (0.5.24) 60 | unf (>= 0.0.5, < 1.0.0) 61 | erubis (2.7.0) 62 | factory_bot (4.10.0) 63 | activesupport (>= 3.0.0) 64 | factory_bot_rails (4.10.0) 65 | factory_bot (~> 4.10.0) 66 | railties (>= 3.0.0) 67 | http-cookie (1.0.2) 68 | domain_name (~> 0.5) 69 | i18n (0.7.0) 70 | jquery-rails (3.1.2) 71 | railties (>= 3.0, < 5.0) 72 | thor (>= 0.14, < 2.0) 73 | json (1.8.6) 74 | mail (2.6.3) 75 | mime-types (>= 1.16, < 3) 76 | method_source (0.9.0) 77 | mime-types (2.4.3) 78 | mini_portile (0.6.2) 79 | minitest (5.6.0) 80 | mysql2 (0.3.18) 81 | netrc (0.10.3) 82 | nokogiri (1.6.6.2) 83 | mini_portile (~> 0.6.0) 84 | pg (0.18.1) 85 | pry (0.11.3) 86 | coderay (~> 1.1.0) 87 | method_source (~> 0.9.0) 88 | rack (1.5.2) 89 | rack-test (0.6.3) 90 | rack (>= 1.0) 91 | rails (4.1.10) 92 | actionmailer (= 4.1.10) 93 | actionpack (= 4.1.10) 94 | actionview (= 4.1.10) 95 | activemodel (= 4.1.10) 96 | activerecord (= 4.1.10) 97 | activesupport (= 4.1.10) 98 | bundler (>= 1.3.0, < 2.0) 99 | railties (= 4.1.10) 100 | sprockets-rails (~> 2.0) 101 | railties (4.1.10) 102 | actionpack (= 4.1.10) 103 | activesupport (= 4.1.10) 104 | rake (>= 0.8.7) 105 | thor (>= 0.18.1, < 2.0) 106 | rake (10.4.2) 107 | rest-client (1.8.0) 108 | http-cookie (>= 1.0.2, < 2.0) 109 | mime-types (>= 1.16, < 3.0) 110 | netrc (~> 0.7) 111 | rspec-core (3.8.0) 112 | rspec-support (~> 3.8.0) 113 | rspec-expectations (3.8.1) 114 | diff-lcs (>= 1.2.0, < 2.0) 115 | rspec-support (~> 3.8.0) 116 | rspec-mocks (3.8.0) 117 | diff-lcs (>= 1.2.0, < 2.0) 118 | rspec-support (~> 3.8.0) 119 | rspec-rails (3.8.0) 120 | actionpack (>= 3.0) 121 | activesupport (>= 3.0) 122 | railties (>= 3.0) 123 | rspec-core (~> 3.8.0) 124 | rspec-expectations (~> 3.8.0) 125 | rspec-mocks (~> 3.8.0) 126 | rspec-support (~> 3.8.0) 127 | rspec-support (3.8.0) 128 | shoulda-matchers (2.8.0) 129 | activesupport (>= 3.0.0) 130 | simplecov (0.10.0) 131 | docile (~> 1.1.0) 132 | json (~> 1.8) 133 | simplecov-html (~> 0.10.0) 134 | simplecov-html (0.10.0) 135 | sprockets (3.0.1) 136 | rack (~> 1.0) 137 | sprockets-rails (2.2.4) 138 | actionpack (>= 3.0) 139 | activesupport (>= 3.0) 140 | sprockets (>= 2.8, < 4.0) 141 | sqlite3 (1.3.13) 142 | term-ansicolor (1.3.0) 143 | tins (~> 1.0) 144 | thor (0.19.1) 145 | thread_safe (0.3.5) 146 | tins (1.3.5) 147 | tzinfo (1.2.2) 148 | thread_safe (~> 0.1) 149 | unf (0.1.4) 150 | unf_ext 151 | unf_ext (0.0.7.1) 152 | xpath (2.0.0) 153 | nokogiri (~> 1.3) 154 | 155 | PLATFORMS 156 | ruby 157 | 158 | DEPENDENCIES 159 | appraisal 160 | capybara (~> 2.2) 161 | coveralls 162 | database_cleaner 163 | factory_bot_rails (~> 4.4) 164 | jquery-rails 165 | mysql2 166 | pg 167 | pry 168 | rails (~> 4.1.10) 169 | rake 170 | redirector! 171 | rspec-rails (~> 3.7) 172 | shoulda-matchers 173 | sqlite3 174 | 175 | BUNDLED WITH 176 | 1.16.1 177 | -------------------------------------------------------------------------------- /gemfiles/rails_419.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "http://rubygems.org" 4 | 5 | gem "jquery-rails" 6 | gem "pry" 7 | gem "rails", "4.1.9" 8 | 9 | gemspec path: "../" 10 | -------------------------------------------------------------------------------- /gemfiles/rails_419.gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: .. 3 | specs: 4 | redirector (1.1.2) 5 | rails (>= 3.1) 6 | 7 | GEM 8 | remote: http://rubygems.org/ 9 | specs: 10 | actionmailer (4.1.9) 11 | actionpack (= 4.1.9) 12 | actionview (= 4.1.9) 13 | mail (~> 2.5, >= 2.5.4) 14 | actionpack (4.1.9) 15 | actionview (= 4.1.9) 16 | activesupport (= 4.1.9) 17 | rack (~> 1.5.2) 18 | rack-test (~> 0.6.2) 19 | actionview (4.1.9) 20 | activesupport (= 4.1.9) 21 | builder (~> 3.1) 22 | erubis (~> 2.7.0) 23 | activemodel (4.1.9) 24 | activesupport (= 4.1.9) 25 | builder (~> 3.1) 26 | activerecord (4.1.9) 27 | activemodel (= 4.1.9) 28 | activesupport (= 4.1.9) 29 | arel (~> 5.0.0) 30 | activesupport (4.1.9) 31 | i18n (~> 0.6, >= 0.6.9) 32 | json (~> 1.7, >= 1.7.7) 33 | minitest (~> 5.1) 34 | thread_safe (~> 0.1) 35 | tzinfo (~> 1.1) 36 | appraisal (2.0.1) 37 | activesupport (>= 3.2.21) 38 | bundler 39 | rake 40 | thor (>= 0.14.0) 41 | arel (5.0.1.20140414130214) 42 | builder (3.2.2) 43 | capybara (2.4.4) 44 | mime-types (>= 1.16) 45 | nokogiri (>= 1.3.3) 46 | rack (>= 1.0.0) 47 | rack-test (>= 0.5.4) 48 | xpath (~> 2.0) 49 | coderay (1.1.2) 50 | coveralls (0.8.1) 51 | json (~> 1.8) 52 | rest-client (>= 1.6.8, < 2) 53 | simplecov (~> 0.10.0) 54 | term-ansicolor (~> 1.3) 55 | thor (~> 0.19.1) 56 | database_cleaner (1.4.1) 57 | diff-lcs (1.3) 58 | docile (1.1.5) 59 | domain_name (0.5.24) 60 | unf (>= 0.0.5, < 1.0.0) 61 | erubis (2.7.0) 62 | factory_bot (4.10.0) 63 | activesupport (>= 3.0.0) 64 | factory_bot_rails (4.10.0) 65 | factory_bot (~> 4.10.0) 66 | railties (>= 3.0.0) 67 | http-cookie (1.0.2) 68 | domain_name (~> 0.5) 69 | i18n (0.7.0) 70 | jquery-rails (3.1.2) 71 | railties (>= 3.0, < 5.0) 72 | thor (>= 0.14, < 2.0) 73 | json (1.8.6) 74 | mail (2.6.3) 75 | mime-types (>= 1.16, < 3) 76 | method_source (0.9.0) 77 | mime-types (2.4.3) 78 | mini_portile (0.6.2) 79 | minitest (5.6.0) 80 | mysql2 (0.3.18) 81 | netrc (0.10.3) 82 | nokogiri (1.6.6.2) 83 | mini_portile (~> 0.6.0) 84 | pg (0.18.1) 85 | pry (0.11.3) 86 | coderay (~> 1.1.0) 87 | method_source (~> 0.9.0) 88 | rack (1.5.2) 89 | rack-test (0.6.3) 90 | rack (>= 1.0) 91 | rails (4.1.9) 92 | actionmailer (= 4.1.9) 93 | actionpack (= 4.1.9) 94 | actionview (= 4.1.9) 95 | activemodel (= 4.1.9) 96 | activerecord (= 4.1.9) 97 | activesupport (= 4.1.9) 98 | bundler (>= 1.3.0, < 2.0) 99 | railties (= 4.1.9) 100 | sprockets-rails (~> 2.0) 101 | railties (4.1.9) 102 | actionpack (= 4.1.9) 103 | activesupport (= 4.1.9) 104 | rake (>= 0.8.7) 105 | thor (>= 0.18.1, < 2.0) 106 | rake (10.4.2) 107 | rest-client (1.8.0) 108 | http-cookie (>= 1.0.2, < 2.0) 109 | mime-types (>= 1.16, < 3.0) 110 | netrc (~> 0.7) 111 | rspec-core (3.8.0) 112 | rspec-support (~> 3.8.0) 113 | rspec-expectations (3.8.1) 114 | diff-lcs (>= 1.2.0, < 2.0) 115 | rspec-support (~> 3.8.0) 116 | rspec-mocks (3.8.0) 117 | diff-lcs (>= 1.2.0, < 2.0) 118 | rspec-support (~> 3.8.0) 119 | rspec-rails (3.8.0) 120 | actionpack (>= 3.0) 121 | activesupport (>= 3.0) 122 | railties (>= 3.0) 123 | rspec-core (~> 3.8.0) 124 | rspec-expectations (~> 3.8.0) 125 | rspec-mocks (~> 3.8.0) 126 | rspec-support (~> 3.8.0) 127 | rspec-support (3.8.0) 128 | shoulda-matchers (2.8.0) 129 | activesupport (>= 3.0.0) 130 | simplecov (0.10.0) 131 | docile (~> 1.1.0) 132 | json (~> 1.8) 133 | simplecov-html (~> 0.10.0) 134 | simplecov-html (0.10.0) 135 | sprockets (3.0.1) 136 | rack (~> 1.0) 137 | sprockets-rails (2.2.4) 138 | actionpack (>= 3.0) 139 | activesupport (>= 3.0) 140 | sprockets (>= 2.8, < 4.0) 141 | sqlite3 (1.3.13) 142 | term-ansicolor (1.3.0) 143 | tins (~> 1.0) 144 | thor (0.19.1) 145 | thread_safe (0.3.5) 146 | tins (1.3.5) 147 | tzinfo (1.2.2) 148 | thread_safe (~> 0.1) 149 | unf (0.1.4) 150 | unf_ext 151 | unf_ext (0.0.7.1) 152 | xpath (2.0.0) 153 | nokogiri (~> 1.3) 154 | 155 | PLATFORMS 156 | ruby 157 | 158 | DEPENDENCIES 159 | appraisal 160 | capybara (~> 2.2) 161 | coveralls 162 | database_cleaner 163 | factory_bot_rails (~> 4.4) 164 | jquery-rails 165 | mysql2 166 | pg 167 | pry 168 | rails (= 4.1.9) 169 | rake 170 | redirector! 171 | rspec-rails (~> 3.7) 172 | shoulda-matchers 173 | sqlite3 174 | 175 | BUNDLED WITH 176 | 1.16.1 177 | -------------------------------------------------------------------------------- /gemfiles/rails_42.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "http://rubygems.org" 4 | 5 | gem "jquery-rails" 6 | gem "pry" 7 | gem "rails", "~> 4.2.1" 8 | 9 | gemspec path: "../" 10 | -------------------------------------------------------------------------------- /gemfiles/rails_42.gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: .. 3 | specs: 4 | redirector (1.1.2) 5 | rails (>= 3.1) 6 | 7 | GEM 8 | remote: http://rubygems.org/ 9 | specs: 10 | actionmailer (4.2.1) 11 | actionpack (= 4.2.1) 12 | actionview (= 4.2.1) 13 | activejob (= 4.2.1) 14 | mail (~> 2.5, >= 2.5.4) 15 | rails-dom-testing (~> 1.0, >= 1.0.5) 16 | actionpack (4.2.1) 17 | actionview (= 4.2.1) 18 | activesupport (= 4.2.1) 19 | rack (~> 1.6) 20 | rack-test (~> 0.6.2) 21 | rails-dom-testing (~> 1.0, >= 1.0.5) 22 | rails-html-sanitizer (~> 1.0, >= 1.0.1) 23 | actionview (4.2.1) 24 | activesupport (= 4.2.1) 25 | builder (~> 3.1) 26 | erubis (~> 2.7.0) 27 | rails-dom-testing (~> 1.0, >= 1.0.5) 28 | rails-html-sanitizer (~> 1.0, >= 1.0.1) 29 | activejob (4.2.1) 30 | activesupport (= 4.2.1) 31 | globalid (>= 0.3.0) 32 | activemodel (4.2.1) 33 | activesupport (= 4.2.1) 34 | builder (~> 3.1) 35 | activerecord (4.2.1) 36 | activemodel (= 4.2.1) 37 | activesupport (= 4.2.1) 38 | arel (~> 6.0) 39 | activesupport (4.2.1) 40 | i18n (~> 0.7) 41 | json (~> 1.7, >= 1.7.7) 42 | minitest (~> 5.1) 43 | thread_safe (~> 0.3, >= 0.3.4) 44 | tzinfo (~> 1.1) 45 | appraisal (2.0.1) 46 | activesupport (>= 3.2.21) 47 | bundler 48 | rake 49 | thor (>= 0.14.0) 50 | arel (6.0.0) 51 | builder (3.2.2) 52 | capybara (2.4.4) 53 | mime-types (>= 1.16) 54 | nokogiri (>= 1.3.3) 55 | rack (>= 1.0.0) 56 | rack-test (>= 0.5.4) 57 | xpath (~> 2.0) 58 | coderay (1.1.2) 59 | coveralls (0.8.1) 60 | json (~> 1.8) 61 | rest-client (>= 1.6.8, < 2) 62 | simplecov (~> 0.10.0) 63 | term-ansicolor (~> 1.3) 64 | thor (~> 0.19.1) 65 | database_cleaner (1.4.1) 66 | diff-lcs (1.3) 67 | docile (1.1.5) 68 | domain_name (0.5.24) 69 | unf (>= 0.0.5, < 1.0.0) 70 | erubis (2.7.0) 71 | factory_bot (4.10.0) 72 | activesupport (>= 3.0.0) 73 | factory_bot_rails (4.10.0) 74 | factory_bot (~> 4.10.0) 75 | railties (>= 3.0.0) 76 | globalid (0.3.5) 77 | activesupport (>= 4.1.0) 78 | http-cookie (1.0.2) 79 | domain_name (~> 0.5) 80 | i18n (0.7.0) 81 | jquery-rails (4.0.3) 82 | rails-dom-testing (~> 1.0) 83 | railties (>= 4.2.0) 84 | thor (>= 0.14, < 2.0) 85 | json (1.8.6) 86 | loofah (2.0.1) 87 | nokogiri (>= 1.5.9) 88 | mail (2.6.3) 89 | mime-types (>= 1.16, < 3) 90 | method_source (0.9.0) 91 | mime-types (2.4.3) 92 | mini_portile (0.6.2) 93 | minitest (5.6.0) 94 | mysql2 (0.3.18) 95 | netrc (0.10.3) 96 | nokogiri (1.6.6.2) 97 | mini_portile (~> 0.6.0) 98 | pg (0.18.1) 99 | pry (0.11.3) 100 | coderay (~> 1.1.0) 101 | method_source (~> 0.9.0) 102 | rack (1.6.0) 103 | rack-test (0.6.3) 104 | rack (>= 1.0) 105 | rails (4.2.1) 106 | actionmailer (= 4.2.1) 107 | actionpack (= 4.2.1) 108 | actionview (= 4.2.1) 109 | activejob (= 4.2.1) 110 | activemodel (= 4.2.1) 111 | activerecord (= 4.2.1) 112 | activesupport (= 4.2.1) 113 | bundler (>= 1.3.0, < 2.0) 114 | railties (= 4.2.1) 115 | sprockets-rails 116 | rails-deprecated_sanitizer (1.0.3) 117 | activesupport (>= 4.2.0.alpha) 118 | rails-dom-testing (1.0.6) 119 | activesupport (>= 4.2.0.beta, < 5.0) 120 | nokogiri (~> 1.6.0) 121 | rails-deprecated_sanitizer (>= 1.0.1) 122 | rails-html-sanitizer (1.0.2) 123 | loofah (~> 2.0) 124 | railties (4.2.1) 125 | actionpack (= 4.2.1) 126 | activesupport (= 4.2.1) 127 | rake (>= 0.8.7) 128 | thor (>= 0.18.1, < 2.0) 129 | rake (10.4.2) 130 | rest-client (1.8.0) 131 | http-cookie (>= 1.0.2, < 2.0) 132 | mime-types (>= 1.16, < 3.0) 133 | netrc (~> 0.7) 134 | rspec-core (3.8.0) 135 | rspec-support (~> 3.8.0) 136 | rspec-expectations (3.8.1) 137 | diff-lcs (>= 1.2.0, < 2.0) 138 | rspec-support (~> 3.8.0) 139 | rspec-mocks (3.8.0) 140 | diff-lcs (>= 1.2.0, < 2.0) 141 | rspec-support (~> 3.8.0) 142 | rspec-rails (3.8.0) 143 | actionpack (>= 3.0) 144 | activesupport (>= 3.0) 145 | railties (>= 3.0) 146 | rspec-core (~> 3.8.0) 147 | rspec-expectations (~> 3.8.0) 148 | rspec-mocks (~> 3.8.0) 149 | rspec-support (~> 3.8.0) 150 | rspec-support (3.8.0) 151 | shoulda-matchers (2.8.0) 152 | activesupport (>= 3.0.0) 153 | simplecov (0.10.0) 154 | docile (~> 1.1.0) 155 | json (~> 1.8) 156 | simplecov-html (~> 0.10.0) 157 | simplecov-html (0.10.0) 158 | sprockets (3.0.1) 159 | rack (~> 1.0) 160 | sprockets-rails (2.2.4) 161 | actionpack (>= 3.0) 162 | activesupport (>= 3.0) 163 | sprockets (>= 2.8, < 4.0) 164 | sqlite3 (1.3.13) 165 | term-ansicolor (1.3.0) 166 | tins (~> 1.0) 167 | thor (0.19.1) 168 | thread_safe (0.3.5) 169 | tins (1.3.5) 170 | tzinfo (1.2.2) 171 | thread_safe (~> 0.1) 172 | unf (0.1.4) 173 | unf_ext 174 | unf_ext (0.0.7.1) 175 | xpath (2.0.0) 176 | nokogiri (~> 1.3) 177 | 178 | PLATFORMS 179 | ruby 180 | 181 | DEPENDENCIES 182 | appraisal 183 | capybara (~> 2.2) 184 | coveralls 185 | database_cleaner 186 | factory_bot_rails (~> 4.4) 187 | jquery-rails 188 | mysql2 189 | pg 190 | pry 191 | rails (~> 4.2.1) 192 | rake 193 | redirector! 194 | rspec-rails (~> 3.7) 195 | shoulda-matchers 196 | sqlite3 197 | 198 | BUNDLED WITH 199 | 1.16.1 200 | -------------------------------------------------------------------------------- /gemfiles/rails_50.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "http://rubygems.org" 4 | 5 | gem "jquery-rails" 6 | gem "pry" 7 | gem "rails", "~> 5.0.6" 8 | 9 | gemspec path: "../" 10 | -------------------------------------------------------------------------------- /gemfiles/rails_50.gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: .. 3 | specs: 4 | redirector (1.1.2) 5 | rails (>= 3.1) 6 | 7 | GEM 8 | remote: http://rubygems.org/ 9 | specs: 10 | actioncable (5.0.7) 11 | actionpack (= 5.0.7) 12 | nio4r (>= 1.2, < 3.0) 13 | websocket-driver (~> 0.6.1) 14 | actionmailer (5.0.7) 15 | actionpack (= 5.0.7) 16 | actionview (= 5.0.7) 17 | activejob (= 5.0.7) 18 | mail (~> 2.5, >= 2.5.4) 19 | rails-dom-testing (~> 2.0) 20 | actionpack (5.0.7) 21 | actionview (= 5.0.7) 22 | activesupport (= 5.0.7) 23 | rack (~> 2.0) 24 | rack-test (~> 0.6.3) 25 | rails-dom-testing (~> 2.0) 26 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 27 | actionview (5.0.7) 28 | activesupport (= 5.0.7) 29 | builder (~> 3.1) 30 | erubis (~> 2.7.0) 31 | rails-dom-testing (~> 2.0) 32 | rails-html-sanitizer (~> 1.0, >= 1.0.3) 33 | activejob (5.0.7) 34 | activesupport (= 5.0.7) 35 | globalid (>= 0.3.6) 36 | activemodel (5.0.7) 37 | activesupport (= 5.0.7) 38 | activerecord (5.0.7) 39 | activemodel (= 5.0.7) 40 | activesupport (= 5.0.7) 41 | arel (~> 7.0) 42 | activesupport (5.0.7) 43 | concurrent-ruby (~> 1.0, >= 1.0.2) 44 | i18n (>= 0.7, < 2) 45 | minitest (~> 5.1) 46 | tzinfo (~> 1.1) 47 | addressable (2.5.2) 48 | public_suffix (>= 2.0.2, < 4.0) 49 | appraisal (2.2.0) 50 | bundler 51 | rake 52 | thor (>= 0.14.0) 53 | arel (7.1.4) 54 | builder (3.2.3) 55 | capybara (2.18.0) 56 | addressable 57 | mini_mime (>= 0.1.3) 58 | nokogiri (>= 1.3.3) 59 | rack (>= 1.0.0) 60 | rack-test (>= 0.5.4) 61 | xpath (>= 2.0, < 4.0) 62 | coderay (1.1.2) 63 | concurrent-ruby (1.0.5) 64 | coveralls (0.8.22) 65 | json (>= 1.8, < 3) 66 | simplecov (~> 0.16.1) 67 | term-ansicolor (~> 1.3) 68 | thor (~> 0.19.4) 69 | tins (~> 1.6) 70 | crass (1.0.4) 71 | database_cleaner (1.7.0) 72 | diff-lcs (1.3) 73 | docile (1.3.1) 74 | erubis (2.7.0) 75 | factory_bot (4.11.1) 76 | activesupport (>= 3.0.0) 77 | factory_bot_rails (4.11.1) 78 | factory_bot (~> 4.11.1) 79 | railties (>= 3.0.0) 80 | globalid (0.4.1) 81 | activesupport (>= 4.2.0) 82 | i18n (1.1.0) 83 | concurrent-ruby (~> 1.0) 84 | jquery-rails (4.3.3) 85 | rails-dom-testing (>= 1, < 3) 86 | railties (>= 4.2.0) 87 | thor (>= 0.14, < 2.0) 88 | json (2.1.0) 89 | loofah (2.2.2) 90 | crass (~> 1.0.2) 91 | nokogiri (>= 1.5.9) 92 | mail (2.7.0) 93 | mini_mime (>= 0.1.1) 94 | method_source (0.9.0) 95 | mini_mime (1.0.1) 96 | mini_portile2 (2.3.0) 97 | minitest (5.11.3) 98 | mysql2 (0.5.2) 99 | nio4r (2.3.1) 100 | nokogiri (1.8.5) 101 | mini_portile2 (~> 2.3.0) 102 | pg (1.1.3) 103 | pry (0.11.3) 104 | coderay (~> 1.1.0) 105 | method_source (~> 0.9.0) 106 | public_suffix (3.0.3) 107 | rack (2.0.5) 108 | rack-test (0.6.3) 109 | rack (>= 1.0) 110 | rails (5.0.7) 111 | actioncable (= 5.0.7) 112 | actionmailer (= 5.0.7) 113 | actionpack (= 5.0.7) 114 | actionview (= 5.0.7) 115 | activejob (= 5.0.7) 116 | activemodel (= 5.0.7) 117 | activerecord (= 5.0.7) 118 | activesupport (= 5.0.7) 119 | bundler (>= 1.3.0) 120 | railties (= 5.0.7) 121 | sprockets-rails (>= 2.0.0) 122 | rails-dom-testing (2.0.3) 123 | activesupport (>= 4.2.0) 124 | nokogiri (>= 1.6) 125 | rails-html-sanitizer (1.0.4) 126 | loofah (~> 2.2, >= 2.2.2) 127 | railties (5.0.7) 128 | actionpack (= 5.0.7) 129 | activesupport (= 5.0.7) 130 | method_source 131 | rake (>= 0.8.7) 132 | thor (>= 0.18.1, < 2.0) 133 | rake (12.3.1) 134 | rspec-core (3.8.0) 135 | rspec-support (~> 3.8.0) 136 | rspec-expectations (3.8.2) 137 | diff-lcs (>= 1.2.0, < 2.0) 138 | rspec-support (~> 3.8.0) 139 | rspec-mocks (3.8.0) 140 | diff-lcs (>= 1.2.0, < 2.0) 141 | rspec-support (~> 3.8.0) 142 | rspec-rails (3.8.0) 143 | actionpack (>= 3.0) 144 | activesupport (>= 3.0) 145 | railties (>= 3.0) 146 | rspec-core (~> 3.8.0) 147 | rspec-expectations (~> 3.8.0) 148 | rspec-mocks (~> 3.8.0) 149 | rspec-support (~> 3.8.0) 150 | rspec-support (3.8.0) 151 | shoulda-matchers (3.1.2) 152 | activesupport (>= 4.0.0) 153 | simplecov (0.16.1) 154 | docile (~> 1.1) 155 | json (>= 1.8, < 3) 156 | simplecov-html (~> 0.10.0) 157 | simplecov-html (0.10.2) 158 | sprockets (3.7.2) 159 | concurrent-ruby (~> 1.0) 160 | rack (> 1, < 3) 161 | sprockets-rails (3.2.1) 162 | actionpack (>= 4.0) 163 | activesupport (>= 4.0) 164 | sprockets (>= 3.0.0) 165 | sqlite3 (1.3.13) 166 | term-ansicolor (1.6.0) 167 | tins (~> 1.0) 168 | thor (0.19.4) 169 | thread_safe (0.3.6) 170 | tins (1.16.3) 171 | tzinfo (1.2.5) 172 | thread_safe (~> 0.1) 173 | websocket-driver (0.6.5) 174 | websocket-extensions (>= 0.1.0) 175 | websocket-extensions (0.1.3) 176 | xpath (3.1.0) 177 | nokogiri (~> 1.8) 178 | 179 | PLATFORMS 180 | ruby 181 | 182 | DEPENDENCIES 183 | appraisal 184 | capybara (~> 2.2) 185 | coveralls 186 | database_cleaner 187 | factory_bot_rails (~> 4.4) 188 | jquery-rails 189 | mysql2 190 | pg 191 | pry 192 | rails (~> 5.0.6) 193 | rake 194 | redirector! 195 | rspec-rails (~> 3.7) 196 | shoulda-matchers 197 | sqlite3 198 | 199 | BUNDLED WITH 200 | 1.16.1 201 | -------------------------------------------------------------------------------- /gemfiles/rails_51.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "http://rubygems.org" 4 | 5 | gem "jquery-rails" 6 | gem "pry" 7 | gem "rails", "~> 5.1.5" 8 | 9 | gemspec path: "../" 10 | -------------------------------------------------------------------------------- /gemfiles/rails_51.gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: .. 3 | specs: 4 | redirector (1.1.2) 5 | rails (>= 3.1) 6 | 7 | GEM 8 | remote: http://rubygems.org/ 9 | specs: 10 | actioncable (5.1.6) 11 | actionpack (= 5.1.6) 12 | nio4r (~> 2.0) 13 | websocket-driver (~> 0.6.1) 14 | actionmailer (5.1.6) 15 | actionpack (= 5.1.6) 16 | actionview (= 5.1.6) 17 | activejob (= 5.1.6) 18 | mail (~> 2.5, >= 2.5.4) 19 | rails-dom-testing (~> 2.0) 20 | actionpack (5.1.6) 21 | actionview (= 5.1.6) 22 | activesupport (= 5.1.6) 23 | rack (~> 2.0) 24 | rack-test (>= 0.6.3) 25 | rails-dom-testing (~> 2.0) 26 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 27 | actionview (5.1.6) 28 | activesupport (= 5.1.6) 29 | builder (~> 3.1) 30 | erubi (~> 1.4) 31 | rails-dom-testing (~> 2.0) 32 | rails-html-sanitizer (~> 1.0, >= 1.0.3) 33 | activejob (5.1.6) 34 | activesupport (= 5.1.6) 35 | globalid (>= 0.3.6) 36 | activemodel (5.1.6) 37 | activesupport (= 5.1.6) 38 | activerecord (5.1.6) 39 | activemodel (= 5.1.6) 40 | activesupport (= 5.1.6) 41 | arel (~> 8.0) 42 | activesupport (5.1.6) 43 | concurrent-ruby (~> 1.0, >= 1.0.2) 44 | i18n (>= 0.7, < 2) 45 | minitest (~> 5.1) 46 | tzinfo (~> 1.1) 47 | addressable (2.5.2) 48 | public_suffix (>= 2.0.2, < 4.0) 49 | appraisal (2.2.0) 50 | bundler 51 | rake 52 | thor (>= 0.14.0) 53 | arel (8.0.0) 54 | builder (3.2.3) 55 | capybara (2.18.0) 56 | addressable 57 | mini_mime (>= 0.1.3) 58 | nokogiri (>= 1.3.3) 59 | rack (>= 1.0.0) 60 | rack-test (>= 0.5.4) 61 | xpath (>= 2.0, < 4.0) 62 | coderay (1.1.2) 63 | concurrent-ruby (1.0.5) 64 | coveralls (0.8.22) 65 | json (>= 1.8, < 3) 66 | simplecov (~> 0.16.1) 67 | term-ansicolor (~> 1.3) 68 | thor (~> 0.19.4) 69 | tins (~> 1.6) 70 | crass (1.0.4) 71 | database_cleaner (1.7.0) 72 | diff-lcs (1.3) 73 | docile (1.3.1) 74 | erubi (1.7.1) 75 | factory_bot (4.11.1) 76 | activesupport (>= 3.0.0) 77 | factory_bot_rails (4.11.1) 78 | factory_bot (~> 4.11.1) 79 | railties (>= 3.0.0) 80 | globalid (0.4.1) 81 | activesupport (>= 4.2.0) 82 | i18n (1.1.0) 83 | concurrent-ruby (~> 1.0) 84 | jquery-rails (4.3.3) 85 | rails-dom-testing (>= 1, < 3) 86 | railties (>= 4.2.0) 87 | thor (>= 0.14, < 2.0) 88 | json (2.1.0) 89 | loofah (2.2.2) 90 | crass (~> 1.0.2) 91 | nokogiri (>= 1.5.9) 92 | mail (2.7.0) 93 | mini_mime (>= 0.1.1) 94 | method_source (0.9.0) 95 | mini_mime (1.0.1) 96 | mini_portile2 (2.3.0) 97 | minitest (5.11.3) 98 | mysql2 (0.5.2) 99 | nio4r (2.3.1) 100 | nokogiri (1.8.5) 101 | mini_portile2 (~> 2.3.0) 102 | pg (1.1.3) 103 | pry (0.11.3) 104 | coderay (~> 1.1.0) 105 | method_source (~> 0.9.0) 106 | public_suffix (3.0.3) 107 | rack (2.0.5) 108 | rack-test (1.1.0) 109 | rack (>= 1.0, < 3) 110 | rails (5.1.6) 111 | actioncable (= 5.1.6) 112 | actionmailer (= 5.1.6) 113 | actionpack (= 5.1.6) 114 | actionview (= 5.1.6) 115 | activejob (= 5.1.6) 116 | activemodel (= 5.1.6) 117 | activerecord (= 5.1.6) 118 | activesupport (= 5.1.6) 119 | bundler (>= 1.3.0) 120 | railties (= 5.1.6) 121 | sprockets-rails (>= 2.0.0) 122 | rails-dom-testing (2.0.3) 123 | activesupport (>= 4.2.0) 124 | nokogiri (>= 1.6) 125 | rails-html-sanitizer (1.0.4) 126 | loofah (~> 2.2, >= 2.2.2) 127 | railties (5.1.6) 128 | actionpack (= 5.1.6) 129 | activesupport (= 5.1.6) 130 | method_source 131 | rake (>= 0.8.7) 132 | thor (>= 0.18.1, < 2.0) 133 | rake (12.3.1) 134 | rspec-core (3.8.0) 135 | rspec-support (~> 3.8.0) 136 | rspec-expectations (3.8.2) 137 | diff-lcs (>= 1.2.0, < 2.0) 138 | rspec-support (~> 3.8.0) 139 | rspec-mocks (3.8.0) 140 | diff-lcs (>= 1.2.0, < 2.0) 141 | rspec-support (~> 3.8.0) 142 | rspec-rails (3.8.0) 143 | actionpack (>= 3.0) 144 | activesupport (>= 3.0) 145 | railties (>= 3.0) 146 | rspec-core (~> 3.8.0) 147 | rspec-expectations (~> 3.8.0) 148 | rspec-mocks (~> 3.8.0) 149 | rspec-support (~> 3.8.0) 150 | rspec-support (3.8.0) 151 | shoulda-matchers (3.1.2) 152 | activesupport (>= 4.0.0) 153 | simplecov (0.16.1) 154 | docile (~> 1.1) 155 | json (>= 1.8, < 3) 156 | simplecov-html (~> 0.10.0) 157 | simplecov-html (0.10.2) 158 | sprockets (3.7.2) 159 | concurrent-ruby (~> 1.0) 160 | rack (> 1, < 3) 161 | sprockets-rails (3.2.1) 162 | actionpack (>= 4.0) 163 | activesupport (>= 4.0) 164 | sprockets (>= 3.0.0) 165 | sqlite3 (1.3.13) 166 | term-ansicolor (1.6.0) 167 | tins (~> 1.0) 168 | thor (0.19.4) 169 | thread_safe (0.3.6) 170 | tins (1.16.3) 171 | tzinfo (1.2.5) 172 | thread_safe (~> 0.1) 173 | websocket-driver (0.6.5) 174 | websocket-extensions (>= 0.1.0) 175 | websocket-extensions (0.1.3) 176 | xpath (3.1.0) 177 | nokogiri (~> 1.8) 178 | 179 | PLATFORMS 180 | ruby 181 | 182 | DEPENDENCIES 183 | appraisal 184 | capybara (~> 2.2) 185 | coveralls 186 | database_cleaner 187 | factory_bot_rails (~> 4.4) 188 | jquery-rails 189 | mysql2 190 | pg 191 | pry 192 | rails (~> 5.1.5) 193 | rake 194 | redirector! 195 | rspec-rails (~> 3.7) 196 | shoulda-matchers 197 | sqlite3 198 | 199 | BUNDLED WITH 200 | 1.16.1 201 | -------------------------------------------------------------------------------- /lib/redirector.rb: -------------------------------------------------------------------------------- 1 | module Redirector 2 | autoload :Middleware, 'redirector/middleware' 3 | autoload :RegexAttribute, 'redirector/regex_attribute' 4 | 5 | mattr_accessor :include_query_in_source 6 | mattr_accessor :preserve_query 7 | mattr_accessor :silence_sql_logs 8 | mattr_accessor :ignored_patterns 9 | 10 | def self.active_record_protected_attributes? 11 | @active_record_protected_attributes ||= Rails.version.to_i < 4 || defined?(ProtectedAttributes) 12 | end 13 | end 14 | 15 | require "redirector/engine" 16 | -------------------------------------------------------------------------------- /lib/redirector/engine.rb: -------------------------------------------------------------------------------- 1 | module Redirector 2 | class Engine < ::Rails::Engine 3 | config.redirector = ActiveSupport::OrderedOptions.new 4 | 5 | initializer "redirector.add_middleware", :after => 'build_middleware_stack' do |app| 6 | app.middleware.insert_before(Rack::Runtime, Redirector::Middleware) 7 | end 8 | 9 | initializer "redirector.apply_options" do |app| 10 | Redirector.include_query_in_source = app.config.redirector.include_query_in_source || false 11 | Redirector.preserve_query = app.config.redirector.preserve_query || false 12 | Redirector.silence_sql_logs = app.config.redirector.silence_sql_logs || false 13 | Redirector.ignored_patterns = app.config.redirector.ignored_patterns || [] 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/redirector/middleware.rb: -------------------------------------------------------------------------------- 1 | module Redirector 2 | class RuleError < StandardError; end 3 | 4 | class Middleware 5 | def initialize(application) 6 | @application = application 7 | end 8 | 9 | def call(environment) 10 | Responder.new(@application, environment).response 11 | end 12 | 13 | class Responder 14 | attr_reader :app, :env 15 | 16 | def initialize(application, environment) 17 | @app = application 18 | @env = environment 19 | end 20 | 21 | def response 22 | if redirect? 23 | redirect_response 24 | else 25 | app.call(env) 26 | end 27 | end 28 | 29 | private 30 | 31 | def redirect? 32 | !ignore_path? && matched_destination.present? 33 | end 34 | 35 | def matched_destination 36 | @matched_destination ||= with_optional_silencing do 37 | RedirectRule.destination_for(request_path, env) 38 | end 39 | end 40 | 41 | def with_optional_silencing(&block) 42 | if Redirector.silence_sql_logs 43 | ActiveRecord::Base.logger.silence { yield } 44 | else 45 | yield 46 | end 47 | end 48 | 49 | def ignore_path? 50 | Redirector.ignored_patterns.any? do |pattern| 51 | request_path.match pattern 52 | end 53 | end 54 | 55 | def request_path 56 | @request_path ||= if Redirector.include_query_in_source 57 | env['ORIGINAL_FULLPATH'] 58 | else 59 | env['PATH_INFO'] 60 | end 61 | end 62 | 63 | def request_host 64 | env['HTTP_HOST'].split(':').first 65 | end 66 | 67 | def request_scheme 68 | env['rack.url_scheme'] 69 | end 70 | 71 | def request_port 72 | @request_port ||= begin 73 | if env['HTTP_HOST'].include?(':') 74 | env['HTTP_HOST'].split(':').last.to_i 75 | end 76 | end 77 | end 78 | 79 | def redirect_response 80 | [301, {'Location' => redirect_url_string}, 81 | [%{You are being redirected #{redirect_url_string}}]] 82 | end 83 | 84 | def destination_uri 85 | URI.parse(matched_destination) 86 | rescue URI::InvalidURIError 87 | rule = RedirectRule.match_for(request_path, env) 88 | raise Redirector::RuleError, "RedirectRule #{rule.id} generated the bad destination: #{matched_destination}" 89 | end 90 | 91 | def redirect_uri 92 | destination_uri.tap do |uri| 93 | uri.scheme ||= request_scheme 94 | uri.host ||= request_host 95 | uri.port ||= request_port if request_port.present? 96 | uri.query ||= env['QUERY_STRING'] if Redirector.preserve_query && env['QUERY_STRING'].present? 97 | end 98 | end 99 | 100 | def redirect_url_string 101 | @redirect_url_string ||= redirect_uri.to_s 102 | end 103 | end 104 | end 105 | end 106 | -------------------------------------------------------------------------------- /lib/redirector/regex_attribute.rb: -------------------------------------------------------------------------------- 1 | module Redirector 2 | module RegexAttribute 3 | 4 | def regex_attribute(attribute_name) 5 | include ValidationMethod 6 | 7 | cattr_accessor :regex_attribute_name 8 | self.regex_attribute_name = attribute_name 9 | 10 | validate :regex_attribute_is_valid_regex 11 | # Not working with rails 5.0.1 12 | if Rails.version.to_i < 5 13 | validates "#{attribute_name}_is_regex".to_sym, :inclusion => { :in => ['0', '1', true, false] } 14 | validates "#{attribute_name}_is_case_sensitive".to_sym, :inclusion => { :in => ['0', '1', true, false] } 15 | end 16 | 17 | define_method("#{regex_attribute_name}_regex") do 18 | if self.send("#{regex_attribute_name}_is_case_sensitive?") 19 | Regexp.compile(self.send(regex_attribute_name)) 20 | else 21 | Regexp.compile(self.send(regex_attribute_name), Regexp::IGNORECASE) 22 | end 23 | end 24 | end 25 | 26 | module ValidationMethod 27 | 28 | protected 29 | 30 | def regex_attribute_is_valid_regex 31 | if self.send("#{regex_attribute_name}_is_regex?") && self.send("#{regex_attribute_name}?") 32 | begin 33 | Regexp.compile(self.send(regex_attribute_name)) 34 | rescue RegexpError 35 | errors.add(regex_attribute_name, 'is an invalid regular expression') 36 | end 37 | end 38 | end 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /lib/redirector/version.rb: -------------------------------------------------------------------------------- 1 | module Redirector 2 | VERSION = "1.1.7" 3 | end 4 | -------------------------------------------------------------------------------- /redirector.gemspec: -------------------------------------------------------------------------------- 1 | $:.push File.expand_path("../lib", __FILE__) 2 | 3 | # Maintain your gem's version: 4 | require "redirector/version" 5 | 6 | # Describe your gem and declare its dependencies: 7 | Gem::Specification.new do |s| 8 | s.name = "redirector" 9 | s.version = Redirector::VERSION 10 | s.authors = ["Brian Landau"] 11 | s.email = ["brian.landau@viget.com"] 12 | s.homepage = "https://github.com/vigetlabs/redirector" 13 | s.summary = "A Rails engine that adds a piece of middleware to the top of your middleware stack that looks for redirect rules stored in your database and redirects you accordingly." 14 | s.description = "A Rails engine that adds a piece of middleware to the top of your middleware stack that looks for redirect rules stored in your database and redirects you accordingly." 15 | 16 | s.files = Dir["{app,config,db,lib}/**/*"] + ["MIT-LICENSE", "Rakefile", 17 | "README.md", "redirector.gemspec", "HISTORY"] 18 | s.test_files = Dir["spec/**/*"] 19 | 20 | s.add_dependency "rails", ">= 3.1" 21 | 22 | s.add_development_dependency "mysql2" 23 | s.add_development_dependency "pg" 24 | 25 | s.add_development_dependency 'rspec-rails', '~> 3.7' 26 | s.add_development_dependency "sqlite3" 27 | s.add_development_dependency 'shoulda-matchers' 28 | s.add_development_dependency 'capybara', '~> 2.2' 29 | s.add_development_dependency 'database_cleaner' 30 | s.add_development_dependency 'factory_bot_rails', '~> 4.4' 31 | s.add_development_dependency 'appraisal' 32 | s.add_development_dependency 'rake' 33 | s.add_development_dependency 'coveralls' 34 | end 35 | -------------------------------------------------------------------------------- /script/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. 3 | 4 | ENGINE_ROOT = File.expand_path('../..', __FILE__) 5 | ENGINE_PATH = File.expand_path('../../lib/redirector/engine', __FILE__) 6 | 7 | require 'rails/all' 8 | require 'rails/engine/commands' 9 | -------------------------------------------------------------------------------- /spec/dummy/README.rdoc: -------------------------------------------------------------------------------- 1 | == Welcome to Rails 2 | 3 | Rails is a web-application framework that includes everything needed to create 4 | database-backed web applications according to the Model-View-Control pattern. 5 | 6 | This pattern splits the view (also called the presentation) into "dumb" 7 | templates that are primarily responsible for inserting pre-built data in between 8 | HTML tags. The model contains the "smart" domain objects (such as Account, 9 | Product, Person, Post) that holds all the business logic and knows how to 10 | persist themselves to a database. The controller handles the incoming requests 11 | (such as Save New Account, Update Product, Show Post) by manipulating the model 12 | and directing data to the view. 13 | 14 | In Rails, the model is handled by what's called an object-relational mapping 15 | layer entitled Active Record. This layer allows you to present the data from 16 | database rows as objects and embellish these data objects with business logic 17 | methods. You can read more about Active Record in 18 | link:files/vendor/rails/activerecord/README.html. 19 | 20 | The controller and view are handled by the Action Pack, which handles both 21 | layers by its two parts: Action View and Action Controller. These two layers 22 | are bundled in a single package due to their heavy interdependence. This is 23 | unlike the relationship between the Active Record and Action Pack that is much 24 | more separate. Each of these packages can be used independently outside of 25 | Rails. You can read more about Action Pack in 26 | link:files/vendor/rails/actionpack/README.html. 27 | 28 | 29 | == Getting Started 30 | 31 | 1. At the command prompt, create a new Rails application: 32 | rails new myapp (where myapp is the application name) 33 | 34 | 2. Change directory to myapp and start the web server: 35 | cd myapp; rails server (run with --help for options) 36 | 37 | 3. Go to http://localhost:3000/ and you'll see: 38 | "Welcome aboard: You're riding Ruby on Rails!" 39 | 40 | 4. Follow the guidelines to start developing your application. You can find 41 | the following resources handy: 42 | 43 | * The Getting Started Guide: http://guides.rubyonrails.org/getting_started.html 44 | * Ruby on Rails Tutorial Book: http://www.railstutorial.org/ 45 | 46 | 47 | == Debugging Rails 48 | 49 | Sometimes your application goes wrong. Fortunately there are a lot of tools that 50 | will help you debug it and get it back on the rails. 51 | 52 | First area to check is the application log files. Have "tail -f" commands 53 | running on the server.log and development.log. Rails will automatically display 54 | debugging and runtime information to these files. Debugging info will also be 55 | shown in the browser on requests from 127.0.0.1. 56 | 57 | You can also log your own messages directly into the log file from your code 58 | using the Ruby logger class from inside your controllers. Example: 59 | 60 | class WeblogController < ActionController::Base 61 | def destroy 62 | @weblog = Weblog.find(params[:id]) 63 | @weblog.destroy 64 | logger.info("#{Time.now} Destroyed Weblog ID ##{@weblog.id}!") 65 | end 66 | end 67 | 68 | The result will be a message in your log file along the lines of: 69 | 70 | Mon Oct 08 14:22:29 +1000 2007 Destroyed Weblog ID #1! 71 | 72 | More information on how to use the logger is at http://www.ruby-doc.org/core/ 73 | 74 | Also, Ruby documentation can be found at http://www.ruby-lang.org/. There are 75 | several books available online as well: 76 | 77 | * Programming Ruby: http://www.ruby-doc.org/docs/ProgrammingRuby/ (Pickaxe) 78 | * Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide) 79 | 80 | These two books will bring you up to speed on the Ruby language and also on 81 | programming in general. 82 | 83 | 84 | == Debugger 85 | 86 | Debugger support is available through the debugger command when you start your 87 | Mongrel or WEBrick server with --debugger. This means that you can break out of 88 | execution at any point in the code, investigate and change the model, and then, 89 | resume execution! You need to install ruby-debug to run the server in debugging 90 | mode. With gems, use sudo gem install ruby-debug. Example: 91 | 92 | class WeblogController < ActionController::Base 93 | def index 94 | @posts = Post.all 95 | debugger 96 | end 97 | end 98 | 99 | So the controller will accept the action, run the first line, then present you 100 | with a IRB prompt in the server window. Here you can do things like: 101 | 102 | >> @posts.inspect 103 | => "[#nil, "body"=>nil, "id"=>"1"}>, 105 | #"Rails", "body"=>"Only ten..", "id"=>"2"}>]" 107 | >> @posts.first.title = "hello from a debugger" 108 | => "hello from a debugger" 109 | 110 | ...and even better, you can examine how your runtime objects actually work: 111 | 112 | >> f = @posts.first 113 | => #nil, "body"=>nil, "id"=>"1"}> 114 | >> f. 115 | Display all 152 possibilities? (y or n) 116 | 117 | Finally, when you're ready to resume execution, you can enter "cont". 118 | 119 | 120 | == Console 121 | 122 | The console is a Ruby shell, which allows you to interact with your 123 | application's domain model. Here you'll have all parts of the application 124 | configured, just like it is when the application is running. You can inspect 125 | domain models, change values, and save to the database. Starting the script 126 | without arguments will launch it in the development environment. 127 | 128 | To start the console, run rails console from the application 129 | directory. 130 | 131 | Options: 132 | 133 | * Passing the -s, --sandbox argument will rollback any modifications 134 | made to the database. 135 | * Passing an environment name as an argument will load the corresponding 136 | environment. Example: rails console production. 137 | 138 | To reload your controllers and models after launching the console run 139 | reload! 140 | 141 | More information about irb can be found at: 142 | link:http://www.rubycentral.org/pickaxe/irb.html 143 | 144 | 145 | == dbconsole 146 | 147 | You can go to the command line of your database directly through rails 148 | dbconsole. You would be connected to the database with the credentials 149 | defined in database.yml. Starting the script without arguments will connect you 150 | to the development database. Passing an argument will connect you to a different 151 | database, like rails dbconsole production. Currently works for MySQL, 152 | PostgreSQL and SQLite 3. 153 | 154 | == Description of Contents 155 | 156 | The default directory structure of a generated Ruby on Rails application: 157 | 158 | |-- app 159 | | |-- assets 160 | | |-- images 161 | | |-- javascripts 162 | | `-- stylesheets 163 | | |-- controllers 164 | | |-- helpers 165 | | |-- mailers 166 | | |-- models 167 | | `-- views 168 | | `-- layouts 169 | |-- config 170 | | |-- environments 171 | | |-- initializers 172 | | `-- locales 173 | |-- db 174 | |-- doc 175 | |-- lib 176 | | `-- tasks 177 | |-- log 178 | |-- public 179 | |-- script 180 | |-- test 181 | | |-- fixtures 182 | | |-- functional 183 | | |-- integration 184 | | |-- performance 185 | | `-- unit 186 | |-- tmp 187 | | |-- cache 188 | | |-- pids 189 | | |-- sessions 190 | | `-- sockets 191 | `-- vendor 192 | |-- assets 193 | `-- stylesheets 194 | `-- plugins 195 | 196 | app 197 | Holds all the code that's specific to this particular application. 198 | 199 | app/assets 200 | Contains subdirectories for images, stylesheets, and JavaScript files. 201 | 202 | app/controllers 203 | Holds controllers that should be named like weblogs_controller.rb for 204 | automated URL mapping. All controllers should descend from 205 | ApplicationController which itself descends from ActionController::Base. 206 | 207 | app/models 208 | Holds models that should be named like post.rb. Models descend from 209 | ActiveRecord::Base by default. 210 | 211 | app/views 212 | Holds the template files for the view that should be named like 213 | weblogs/index.html.erb for the WeblogsController#index action. All views use 214 | eRuby syntax by default. 215 | 216 | app/views/layouts 217 | Holds the template files for layouts to be used with views. This models the 218 | common header/footer method of wrapping views. In your views, define a layout 219 | using the layout :default and create a file named default.html.erb. 220 | Inside default.html.erb, call <% yield %> to render the view using this 221 | layout. 222 | 223 | app/helpers 224 | Holds view helpers that should be named like weblogs_helper.rb. These are 225 | generated for you automatically when using generators for controllers. 226 | Helpers can be used to wrap functionality for your views into methods. 227 | 228 | config 229 | Configuration files for the Rails environment, the routing map, the database, 230 | and other dependencies. 231 | 232 | db 233 | Contains the database schema in schema.rb. db/migrate contains all the 234 | sequence of Migrations for your schema. 235 | 236 | doc 237 | This directory is where your application documentation will be stored when 238 | generated using rake doc:app 239 | 240 | lib 241 | Application specific libraries. Basically, any kind of custom code that 242 | doesn't belong under controllers, models, or helpers. This directory is in 243 | the load path. 244 | 245 | public 246 | The directory available for the web server. Also contains the dispatchers and the 247 | default HTML files. This should be set as the DOCUMENT_ROOT of your web 248 | server. 249 | 250 | script 251 | Helper scripts for automation and generation. 252 | 253 | test 254 | Unit and functional tests along with fixtures. When using the rails generate 255 | command, template test files will be generated for you and placed in this 256 | directory. 257 | 258 | vendor 259 | External libraries that the application depends on. Also includes the plugins 260 | subdirectory. If the app has frozen rails, those gems also go here, under 261 | vendor/rails/. This directory is in the load path. 262 | -------------------------------------------------------------------------------- /spec/dummy/Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | # Add your own tasks in files placed in lib/tasks ending in .rake, 3 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 4 | 5 | require File.expand_path('../config/application', __FILE__) 6 | 7 | Dummy::Application.load_tasks 8 | -------------------------------------------------------------------------------- /spec/dummy/app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // the compiled file. 9 | // 10 | // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD 11 | // GO AFTER THE REQUIRES BELOW. 12 | // 13 | //= require jquery 14 | //= require jquery_ujs 15 | //= require_tree . 16 | -------------------------------------------------------------------------------- /spec/dummy/app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 6 | * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the top of the 9 | * compiled file, but it's generally better to create a new file per style scope. 10 | * 11 | *= require_self 12 | *= require_tree . 13 | */ 14 | -------------------------------------------------------------------------------- /spec/dummy/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | protect_from_forgery 3 | end 4 | -------------------------------------------------------------------------------- /spec/dummy/app/controllers/news_controller.rb: -------------------------------------------------------------------------------- 1 | class NewsController < ApplicationController 2 | def index 3 | render :text => "INDEX" 4 | end 5 | 6 | def show 7 | render :text => "SHOW" 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/dummy/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /spec/dummy/app/mailers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vigetlabs/redirector/e3add13562df57b4c9591c138dacbb8c30b582b0/spec/dummy/app/mailers/.gitkeep -------------------------------------------------------------------------------- /spec/dummy/app/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vigetlabs/redirector/e3add13562df57b4c9591c138dacbb8c30b582b0/spec/dummy/app/models/.gitkeep -------------------------------------------------------------------------------- /spec/dummy/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dummy 5 | <%= stylesheet_link_tag "application", :media => "all" %> 6 | <%= javascript_include_tag "application" %> 7 | <%= csrf_meta_tags %> 8 | 9 | 10 | 11 | <%= yield %> 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /spec/dummy/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run Dummy::Application 5 | -------------------------------------------------------------------------------- /spec/dummy/config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | require 'rails/all' 4 | 5 | Bundler.require 6 | require "redirector" 7 | 8 | module Dummy 9 | class Application < Rails::Application 10 | # Settings in config/environments/* take precedence over those specified here. 11 | # Application configuration should go into files in config/initializers 12 | # -- all .rb files in that directory are automatically loaded. 13 | 14 | # Custom directories with classes and modules you want to be autoloadable. 15 | # config.autoload_paths += %W(#{config.root}/extras) 16 | 17 | # Only load the plugins named here, in the order given (default is alphabetical). 18 | # :all can be used as a placeholder for all plugins not explicitly named. 19 | # config.plugins = [ :exception_notification, :ssl_requirement, :all ] 20 | 21 | # Activate observers that should always be running. 22 | # config.active_record.observers = :cacher, :garbage_collector, :forum_observer 23 | 24 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 25 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 26 | # config.time_zone = 'Central Time (US & Canada)' 27 | 28 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 29 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 30 | # config.i18n.default_locale = :de 31 | 32 | # Configure the default encoding used in templates for Ruby 1.9. 33 | config.encoding = "utf-8" 34 | 35 | # Configure sensitive parameters which will be filtered from the log file. 36 | config.filter_parameters += [:password] 37 | 38 | # Enable escaping HTML in JSON. 39 | config.active_support.escape_html_entities_in_json = true 40 | 41 | # Use SQL instead of Active Record's schema dumper when creating the database. 42 | # This is necessary if your schema can't be completely dumped by the schema dumper, 43 | # like if you have constraints or database-specific column types 44 | # config.active_record.schema_format = :sql 45 | 46 | # Enforce whitelist mode for mass assignment. 47 | # This will create an empty whitelist of attributes available for mass-assignment for all models 48 | # in your app. As such, your models will need to explicitly whitelist or blacklist accessible 49 | # parameters by using an attr_accessible or attr_protected declaration. 50 | # config.active_record.whitelist_attributes = true 51 | 52 | # Enable the asset pipeline 53 | # config.assets.enabled = true 54 | 55 | # Version of your assets, change this if you want to expire all your assets 56 | # config.assets.version = '1.0' 57 | end 58 | end 59 | 60 | -------------------------------------------------------------------------------- /spec/dummy/config/boot.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__) 3 | 4 | require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) 5 | 6 | $:.unshift File.expand_path('../../../../lib', __FILE__) 7 | -------------------------------------------------------------------------------- /spec/dummy/config/database.travis.yml: -------------------------------------------------------------------------------- 1 | mysql: &mysql 2 | adapter: mysql2 3 | username: travis 4 | encoding: utf8 5 | reconnect: false 6 | password: 7 | database: redirector_dummy_<%= Rails.env %> 8 | 9 | postgresql: &postgresql 10 | adapter: postgresql 11 | username: postgres 12 | password: 13 | database: redirector_dummy_<%= Rails.env %> 14 | encoding: unicode 15 | min_messages: warning 16 | 17 | defaults: &defaults 18 | pool: 5 19 | timeout: 5000 20 | <<: *<%= ENV['DB'] || "mysql" %> 21 | 22 | development: 23 | <<: *defaults 24 | 25 | test: 26 | <<: *defaults 27 | -------------------------------------------------------------------------------- /spec/dummy/config/database.yml.example: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: mysql2 3 | encoding: utf8 4 | reconnect: false 5 | database: redirector_dummy_development 6 | pool: 5 7 | username: travis 8 | password: 9 | 10 | test: 11 | adapter: mysql2 12 | encoding: utf8 13 | reconnect: false 14 | database: redirector_dummy_test 15 | pool: 5 16 | username: travis 17 | password: 18 | -------------------------------------------------------------------------------- /spec/dummy/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the rails application 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the rails application 5 | Dummy::Application.initialize! 6 | -------------------------------------------------------------------------------- /spec/dummy/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Dummy::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Log error messages when you accidentally call methods on nil. 10 | config.whiny_nils = true 11 | 12 | # Show full error reports and disable caching 13 | config.consider_all_requests_local = true 14 | config.action_controller.perform_caching = false 15 | 16 | # Don't care if the mailer can't send 17 | config.action_mailer.raise_delivery_errors = false 18 | 19 | # Print deprecation notices to the Rails logger 20 | config.active_support.deprecation = :log 21 | 22 | # Only use best-standards-support built into browsers 23 | config.action_dispatch.best_standards_support = :builtin 24 | 25 | # Raise exception on mass assignment protection for Active Record models 26 | # config.active_record.mass_assignment_sanitizer = :strict 27 | 28 | # Log the query plan for queries taking more than this (works 29 | # with SQLite, MySQL, and PostgreSQL) 30 | # config.active_record.auto_explain_threshold_in_seconds = 0.5 31 | 32 | # Do not compress assets 33 | config.assets.compress = false 34 | 35 | # Expands the lines which load the assets 36 | config.assets.debug = true 37 | 38 | config.eager_load = false 39 | end 40 | -------------------------------------------------------------------------------- /spec/dummy/config/environments/production.rb: -------------------------------------------------------------------------------- 1 | Dummy::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # Code is not reloaded between requests 5 | config.cache_classes = true 6 | 7 | # Full error reports are disabled and caching is turned on 8 | config.consider_all_requests_local = false 9 | config.action_controller.perform_caching = true 10 | 11 | # Disable Rails's static asset server (Apache or nginx will already do this) 12 | config.serve_static_assets = false 13 | 14 | # Compress JavaScripts and CSS 15 | config.assets.compress = true 16 | 17 | # Don't fallback to assets pipeline if a precompiled asset is missed 18 | config.assets.compile = false 19 | 20 | # Generate digests for assets URLs 21 | config.assets.digest = true 22 | 23 | # Defaults to nil and saved in location specified by config.assets.prefix 24 | # config.assets.manifest = YOUR_PATH 25 | 26 | # Specifies the header that your server uses for sending files 27 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache 28 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx 29 | 30 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 31 | # config.force_ssl = true 32 | 33 | # See everything in the log (default is :info) 34 | # config.log_level = :debug 35 | 36 | # Prepend all log lines with the following tags 37 | # config.log_tags = [ :subdomain, :uuid ] 38 | 39 | # Use a different logger for distributed setups 40 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) 41 | 42 | # Use a different cache store in production 43 | # config.cache_store = :mem_cache_store 44 | 45 | # Enable serving of images, stylesheets, and JavaScripts from an asset server 46 | # config.action_controller.asset_host = "http://assets.example.com" 47 | 48 | # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) 49 | # config.assets.precompile += %w( search.js ) 50 | 51 | # Disable delivery errors, bad email addresses will be ignored 52 | # config.action_mailer.raise_delivery_errors = false 53 | 54 | # Enable threaded mode 55 | # config.threadsafe! 56 | 57 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 58 | # the I18n.default_locale when a translation can not be found) 59 | config.i18n.fallbacks = true 60 | 61 | # Send deprecation notices to registered listeners 62 | config.active_support.deprecation = :notify 63 | 64 | # Log the query plan for queries taking more than this (works 65 | # with SQLite, MySQL, and PostgreSQL) 66 | # config.active_record.auto_explain_threshold_in_seconds = 0.5 67 | end 68 | -------------------------------------------------------------------------------- /spec/dummy/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | Dummy::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Configure static asset server for tests with Cache-Control for performance 11 | config.serve_static_assets = true 12 | config.static_cache_control = "public, max-age=3600" 13 | 14 | # Log error messages when you accidentally call methods on nil 15 | config.whiny_nils = true 16 | 17 | # Show full error reports and disable caching 18 | config.consider_all_requests_local = true 19 | config.action_controller.perform_caching = false 20 | 21 | # Raise exceptions instead of rendering exception templates 22 | config.action_dispatch.show_exceptions = true 23 | 24 | # Disable request forgery protection in test environment 25 | config.action_controller.allow_forgery_protection = false 26 | 27 | # Tell Action Mailer not to deliver emails to the real world. 28 | # The :test delivery method accumulates sent emails in the 29 | # ActionMailer::Base.deliveries array. 30 | config.action_mailer.delivery_method = :test 31 | 32 | # Raise exception on mass assignment protection for Active Record models 33 | # config.active_record.mass_assignment_sanitizer = :strict 34 | 35 | # Print deprecation notices to the stderr 36 | config.active_support.deprecation = :stderr 37 | 38 | config.eager_load = false 39 | end 40 | -------------------------------------------------------------------------------- /spec/dummy/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| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /spec/dummy/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 4 | # (all these examples are active by default): 5 | # ActiveSupport::Inflector.inflections do |inflect| 6 | # inflect.plural /^(ox)$/i, '\1en' 7 | # inflect.singular /^(ox)en/i, '\1' 8 | # inflect.irregular 'person', 'people' 9 | # inflect.uncountable %w( fish sheep ) 10 | # end 11 | # 12 | # These inflection rules are supported but not enabled by default: 13 | # ActiveSupport::Inflector.inflections do |inflect| 14 | # inflect.acronym 'RESTful' 15 | # end 16 | -------------------------------------------------------------------------------- /spec/dummy/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 | # Mime::Type.register_alias "text/html", :iphone 6 | -------------------------------------------------------------------------------- /spec/dummy/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 | Dummy::Application.config.secret_token = 'df8e1d3ef71b6c05af125acba6bb1df5b94c7069938b3ec1f3dcfe5f0d5c7cc6356ae70b625f716f24fd166d913619a02abc3d78f7177ef5f00cd48fd90f7fe2' 8 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Dummy::Application.config.session_store :cookie_store, key: '_dummy_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 | # Dummy::Application.config.session_store :active_record_store 9 | -------------------------------------------------------------------------------- /spec/dummy/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 | # Disable root element in JSON by default. 12 | ActiveSupport.on_load(:active_record) do 13 | self.include_root_in_json = false 14 | end 15 | -------------------------------------------------------------------------------- /spec/dummy/config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Sample localization file for English. Add more files in this directory for other locales. 2 | # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. 3 | 4 | en: 5 | hello: "Hello world" 6 | -------------------------------------------------------------------------------- /spec/dummy/config/routes.rb: -------------------------------------------------------------------------------- 1 | Dummy::Application.routes.draw do 2 | resources :news, :only => [:index, :show] 3 | end 4 | -------------------------------------------------------------------------------- /spec/dummy/db/schema.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # This file is auto-generated from the current state of the database. Instead 3 | # of editing this file, please use the migrations feature of Active Record to 4 | # incrementally modify your database, and then regenerate this schema definition. 5 | # 6 | # Note that this schema.rb definition is the authoritative source for your 7 | # database schema. If you need to create the application database on another 8 | # system, you should be using db:schema:load, not running all the migrations 9 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations 10 | # you'll amass, the slower it'll run and the greater likelihood for issues). 11 | # 12 | # It's strongly recommended that you check this file into your version control system. 13 | 14 | ActiveRecord::Schema.define(version: 20120823163756) do 15 | 16 | create_table "redirect_rules", force: :cascade do |t| 17 | t.string "source", limit: 255, null: false 18 | t.boolean "source_is_regex", limit: 1, default: false, null: false 19 | t.boolean "source_is_case_sensitive", limit: 1, default: false, null: false 20 | t.string "destination", limit: 255, null: false 21 | t.boolean "active", limit: 1, default: false 22 | t.datetime "created_at" 23 | t.datetime "updated_at" 24 | end 25 | 26 | add_index "redirect_rules", ["active"], name: "index_redirect_rules_on_active", using: :btree 27 | add_index "redirect_rules", ["source"], name: "index_redirect_rules_on_source", using: :btree 28 | add_index "redirect_rules", ["source_is_case_sensitive"], name: "index_redirect_rules_on_source_is_case_sensitive", using: :btree 29 | add_index "redirect_rules", ["source_is_regex"], name: "index_redirect_rules_on_source_is_regex", using: :btree 30 | 31 | create_table "request_environment_rules", force: :cascade do |t| 32 | t.integer "redirect_rule_id", limit: 4, null: false 33 | t.string "environment_key_name", limit: 255, null: false 34 | t.string "environment_value", limit: 255, null: false 35 | t.boolean "environment_value_is_regex", limit: 1, default: false, null: false 36 | t.boolean "environment_value_is_case_sensitive", limit: 1, default: true, null: false 37 | t.datetime "created_at" 38 | t.datetime "updated_at" 39 | end 40 | 41 | add_index "request_environment_rules", ["redirect_rule_id"], name: "index_request_environment_rules_on_redirect_rule_id", using: :btree 42 | 43 | end 44 | -------------------------------------------------------------------------------- /spec/dummy/lib/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vigetlabs/redirector/e3add13562df57b4c9591c138dacbb8c30b582b0/spec/dummy/lib/assets/.gitkeep -------------------------------------------------------------------------------- /spec/dummy/log/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vigetlabs/redirector/e3add13562df57b4c9591c138dacbb8c30b582b0/spec/dummy/log/.gitkeep -------------------------------------------------------------------------------- /spec/dummy/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

The page you were looking for doesn't exist.

23 |

You may have mistyped the address or the page may have moved.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /spec/dummy/public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

The change you wanted was rejected.

23 |

Maybe you tried to change something you didn't have access to.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /spec/dummy/public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

We're sorry, but something went wrong.

23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /spec/dummy/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vigetlabs/redirector/e3add13562df57b4c9591c138dacbb8c30b582b0/spec/dummy/public/favicon.ico -------------------------------------------------------------------------------- /spec/dummy/script/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. 3 | 4 | APP_PATH = File.expand_path('../../config/application', __FILE__) 5 | require File.expand_path('../../config/boot', __FILE__) 6 | require 'rails/commands' 7 | -------------------------------------------------------------------------------- /spec/factories/redirect_rules.rb: -------------------------------------------------------------------------------- 1 | # Read about factories at https://github.com/thoughtbot/factory_bot 2 | 3 | FactoryBot.define do 4 | factory :redirect_rule do 5 | active true 6 | source_is_regex false 7 | source '/catchy_thingy' 8 | destination 'http://www.example.com/products/1' 9 | 10 | factory :redirect_rule_regex do 11 | source_is_regex true 12 | source '[A-Za-z0-9_]+shiny\/([A-Za-z0-9_]+)' 13 | destination 'http://www.example.com/news/$1' 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/factories/request_environment_rules.rb: -------------------------------------------------------------------------------- 1 | # Read about factories at https://github.com/thoughtbot/factory_bot 2 | 3 | FactoryBot.define do 4 | factory :request_environment_rule do 5 | redirect_rule 6 | environment_key_name "SERVER_NAME" 7 | environment_value "example.com" 8 | 9 | factory :request_environment_rule_regex do 10 | environment_key_name "QUERY_STRING" 11 | environment_value "something=value" 12 | environment_value_is_regex true 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/features/middleware_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'Redirector middleware', :type => :feature do 4 | before do 5 | create(:redirect_rule, :destination => '/news/5', :source => '/my_custom_url') 6 | create(:redirect_rule_regex, :destination => '/news/$1', :source => '/my_custom_url/([A-Za-z0-9_]+)') 7 | create(:redirect_rule_regex, :destination => '/news', :source => 'categoryID=12345') 8 | end 9 | 10 | it 'correctly redirects the visitor for an exact match rule' do 11 | visit '/my_custom_url' 12 | expect(current_path).to eq('/news/5') 13 | end 14 | 15 | it 'correctly redirects the visitor for a regex match rule' do 16 | visit '/my_custom_url/20' 17 | expect(current_path).to eq('/news/20') 18 | end 19 | 20 | it 'should not do the query string match if the Redirector.include_query_in_source is false' do 21 | visit '/my_old_url?categoryID=12345' 22 | expect(current_path).to eq('/my_old_url') 23 | end 24 | 25 | it 'should do the query string match if the Redirector.include_query_in_source is true' do 26 | original_option = Redirector.include_query_in_source 27 | Redirector.include_query_in_source = true 28 | visit '/my_old_url?categoryID=12345' 29 | expect(current_path).to eq('/news') 30 | Redirector.include_query_in_source = original_option 31 | end 32 | 33 | it 'should preserve the query string if the Redirector.preserve_query is true' do 34 | original_option = Redirector.preserve_query 35 | Redirector.preserve_query = true 36 | visit '/my_custom_url/20?categoryID=43257' 37 | uri = URI.parse(current_url) 38 | expect(uri.query).to eq('categoryID=43257') 39 | expect(current_path).to eq('/news/20') 40 | Redirector.preserve_query = original_option 41 | end 42 | 43 | it 'should stil work with silenced ActiveRecord logs' do 44 | original_option = Redirector.silence_sql_logs 45 | Redirector.silence_sql_logs = true 46 | visit '/my_custom_url/20' 47 | expect(current_path).to eq('/news/20') 48 | Redirector.preserve_query = original_option 49 | end 50 | 51 | it 'handles requests with or without a port specified' do 52 | Capybara.app_host = 'http://example.com' 53 | 54 | visit '/my_custom_url' 55 | expect(current_url).to eq('http://example.com/news/5') 56 | 57 | Capybara.app_host = 'http://example.com:3000' 58 | 59 | visit '/my_custom_url' 60 | expect(current_url).to eq('http://example.com:3000/news/5') 61 | end 62 | 63 | it 'handles https requests' do 64 | Capybara.app_host = 'https://example.com' 65 | 66 | visit '/my_custom_url' 67 | expect(current_url).to eq('https://example.com/news/5') 68 | end 69 | 70 | it 'foregoes search if ignored path pattern is detected' do 71 | original_option = Redirector.ignored_patterns 72 | Redirector.ignored_patterns = [/^\/my_custom_url\/.+/] 73 | 74 | visit '/my_custom_url/20' 75 | expect(current_path).to eq('/my_custom_url/20') 76 | 77 | Redirector.ignored_patterns = original_option 78 | end 79 | 80 | unless Rails.version =~ /\A4\.2\.\d\z/ 81 | it 'handles invalid URIs properly' do 82 | bad_rule = create(:redirect_rule_regex, 83 | :destination => 'http://www.example.com/invalid)e2', 84 | :source => '^/custom(.*)$', 85 | ) 86 | 87 | begin 88 | visit '/custome2' 89 | rescue Redirector::RuleError => e 90 | expect(e.message).to eq("RedirectRule #{bad_rule.id} generated the bad destination: http://www.example.com)e2") 91 | end 92 | end 93 | end 94 | end 95 | -------------------------------------------------------------------------------- /spec/models/redirect_rule_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe RedirectRule do 4 | subject { create(:redirect_rule) } 5 | let!(:rule) { subject } 6 | 7 | it { is_expected.to have_many(:request_environment_rules) } 8 | 9 | it { is_expected.to accept_nested_attributes_for(:request_environment_rules) } 10 | 11 | it { is_expected.to validate_presence_of(:source) } 12 | it { is_expected.to validate_presence_of(:destination) } 13 | 14 | it { is_expected.to allow_value('0').for(:active) } 15 | it { is_expected.to allow_value('1').for(:active) } 16 | it { is_expected.to allow_value(true).for(:active) } 17 | it { is_expected.to allow_value(false).for(:active) } 18 | 19 | it { is_expected.to allow_value('0').for(:source_is_regex) } 20 | it { is_expected.to allow_value('1').for(:source_is_regex) } 21 | it { is_expected.to allow_value(true).for(:source_is_regex) } 22 | it { is_expected.to allow_value(false).for(:source_is_regex) } 23 | 24 | it { is_expected.to allow_value('0').for(:source_is_case_sensitive) } 25 | it { is_expected.to allow_value('1').for(:source_is_case_sensitive) } 26 | it { is_expected.to allow_value(true).for(:source_is_case_sensitive) } 27 | it { is_expected.to allow_value(false).for(:source_is_case_sensitive) } 28 | 29 | it 'should not allow an invalid regex' do 30 | new_rule = RedirectRule.new( 31 | :source => '[', 32 | :source_is_regex => true, 33 | :destination => 'http://www.example.com', 34 | :active => true 35 | ) 36 | new_rule.validate 37 | expect(new_rule.errors[:source]).to eq(['is an invalid regular expression']) 38 | end 39 | 40 | describe 'strip_source_whitespace before_save callback' do 41 | it 'strips leading and trailing whitespace when saved' do 42 | subject = build(:redirect_rule, :source => ' /needs-stripping ') 43 | 44 | subject.save 45 | expect(subject.reload.source).to eq('/needs-stripping') 46 | end 47 | end 48 | 49 | describe 'strip_destination_whitespace before_save callback' do 50 | it 'strips leading and trailing whitespace when saved' do 51 | subject = build(:redirect_rule, :destination => ' /needs-stripping ') 52 | 53 | subject.save 54 | expect(subject.reload.destination).to eq('/needs-stripping') 55 | end 56 | end 57 | 58 | describe '.match_for' do 59 | it 'returns nil if there is no matching rule' do 60 | expect(RedirectRule.match_for('/someplace', {})).to be_nil 61 | end 62 | 63 | it 'returns the rule if there is a matching rule' do 64 | expect(RedirectRule.match_for('/catchy_thingy', {})).to eq(subject) 65 | end 66 | 67 | context 'for a case sensitive match' do 68 | let!(:case_sensitive_rule) { create(:redirect_rule, :source_is_case_sensitive => true, :source => '/Case-Does-Matter') } 69 | 70 | it 'returns the rule if it matches the case' do 71 | expect(RedirectRule.match_for('/Case-Does-Matter', {})).to eq(case_sensitive_rule) 72 | end 73 | 74 | it 'returns nil if it does not match the case' do 75 | expect(RedirectRule.match_for('/case-does-matter', {})).to be_nil 76 | end 77 | end 78 | 79 | context 'for a case insensitive match' do 80 | let!(:case_insensitive_rule) { create(:redirect_rule, :source_is_case_sensitive => false, :source => '/Case-Does-Not-Matter') } 81 | 82 | it 'returns the rule if it matches the case' do 83 | expect(RedirectRule.match_for('/Case-Does-Not-Matter', {})).to eq(case_insensitive_rule) 84 | end 85 | 86 | it 'returns the rule if it does not match the case' do 87 | expect(RedirectRule.match_for('/case-does-not-matter', {})).to eq(case_insensitive_rule) 88 | end 89 | end 90 | 91 | context 'for a case sensitive regex match' do 92 | let!(:regex_rule){ create(:redirect_rule_regex, :source_is_case_sensitive => true) } 93 | 94 | it 'returns the rule if it matches the case' do 95 | expect(RedirectRule.match_for('/new_shiny/from_company', {})).to eq(regex_rule) 96 | end 97 | 98 | it 'returns nil if it does not match the case' do 99 | expect(RedirectRule.match_for('/new_SHINY/from_company', {})).to be_nil 100 | end 101 | end 102 | 103 | context 'for a case insensitive regex match' do 104 | let!(:regex_rule){ create(:redirect_rule_regex) } 105 | 106 | it 'returns the rule if it matches the case' do 107 | expect(RedirectRule.match_for('/new_shiny/from_company', {})).to eq(regex_rule) 108 | end 109 | 110 | it 'returns the rule if it does not match the case' do 111 | expect(RedirectRule.match_for('/new_SHINY/from_company', {})).to eq(regex_rule) 112 | end 113 | end 114 | 115 | context 'with a rule with one environment condition' do 116 | before do 117 | create(:request_environment_rule, :redirect_rule => subject) 118 | end 119 | 120 | it 'should find the rule if it matches' do 121 | expect(RedirectRule.match_for('/catchy_thingy', {'SERVER_NAME' => 'example.com'})).to eq(subject) 122 | end 123 | 124 | it 'should not find the rule if there is no match' do 125 | expect(RedirectRule.match_for('/catchy_thingy', {'SERVER_NAME' => 'example.ca'})).to be_nil 126 | end 127 | end 128 | 129 | context 'with a rule with multiple environment conditions' do 130 | before do 131 | create(:request_environment_rule, :redirect_rule => subject) 132 | create(:request_environment_rule_regex, :redirect_rule => subject) 133 | end 134 | 135 | it 'should find the rule if it matches' do 136 | expect(RedirectRule.match_for('/catchy_thingy', {'SERVER_NAME' => 'example.com', 137 | 'QUERY_STRING' => 's=bogus&something=value'})).to eq(subject) 138 | end 139 | 140 | it 'should not find the rule if there is no match' do 141 | expect(RedirectRule.match_for('/catchy_thingy', {'SERVER_NAME' => 'example.com', 142 | "QUERY_STRING" => 's=bogus&something=wrong'})).to be_nil 143 | end 144 | end 145 | 146 | context 'with multiple rules with multiple environment conditions' do 147 | let!(:rule2){ create(:redirect_rule) } 148 | before do 149 | create(:request_environment_rule, :redirect_rule => subject) 150 | create(:request_environment_rule_regex, :redirect_rule => subject) 151 | create(:request_environment_rule, :redirect_rule => rule2) 152 | create(:request_environment_rule_regex, :redirect_rule => rule2, 153 | :environment_value => 'another=value') 154 | end 155 | 156 | it 'should find the rule if it matches' do 157 | expect(RedirectRule.match_for('/catchy_thingy', {'SERVER_NAME' => 'example.com', 158 | 'QUERY_STRING' => 's=bogus&something=value'})).to eq(subject) 159 | end 160 | 161 | it 'should find the other rule if it matches' do 162 | expect(RedirectRule.match_for('/catchy_thingy', {'SERVER_NAME' => 'example.com', 163 | 'QUERY_STRING' => 's=bogus&another=value'})).to eq(rule2) 164 | end 165 | 166 | it 'should not find the rule if there is no match' do 167 | expect(RedirectRule.match_for('/catchy_thingy', {'SERVER_NAME' => 'example.com', 168 | "QUERY_STRING" => 's=bogus&something=wrong'})).to be_nil 169 | end 170 | end 171 | 172 | context 'with a regex rule that also matches an exact string match' do 173 | let!(:regex_rule){ create(:redirect_rule_regex, :source => '[A-Za-z0-9]_thingy') } 174 | 175 | it 'should return the exact match' do 176 | expect(RedirectRule.match_for('/catchy_thingy', {})).to eq(subject) 177 | end 178 | end 179 | end 180 | 181 | describe '.destination_for' do 182 | let!(:regex_rule) { create(:redirect_rule_regex) } 183 | 184 | it 'should find a regex match' do 185 | expect(RedirectRule.destination_for('/new_shiny/from_company', {})).to eq('http://www.example.com/news/from_company') 186 | end 187 | 188 | it 'should find a string match' do 189 | expect(RedirectRule.destination_for('/catchy_thingy', {})).to eq('http://www.example.com/products/1') 190 | end 191 | 192 | it 'should return nil if there is no matching rule' do 193 | expect(RedirectRule.destination_for('/someplace', {})).to be_nil 194 | end 195 | end 196 | 197 | describe '#evaluated_destination_for' do 198 | let(:regex_rule) { create(:redirect_rule_regex) } 199 | 200 | it 'returns the destination for a non regex rule' do 201 | expect(subject.evaluated_destination_for('/catchy_thingy')).to eq('http://www.example.com/products/1') 202 | end 203 | 204 | it 'returns the evaluated destination for a regex rule' do 205 | expect(regex_rule.evaluated_destination_for('/new_shiny/from_company')).to eq('http://www.example.com/news/from_company') 206 | end 207 | end 208 | end 209 | -------------------------------------------------------------------------------- /spec/models/request_environment_rule_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe RequestEnvironmentRule do 4 | subject { create(:request_environment_rule) } 5 | 6 | it { is_expected.to belong_to(:redirect_rule) } 7 | 8 | it { is_expected.to validate_presence_of(:redirect_rule) } 9 | it { is_expected.to validate_presence_of(:environment_key_name) } 10 | it { is_expected.to validate_presence_of(:environment_value) } 11 | 12 | it { is_expected.to allow_value('0').for(:environment_value_is_regex) } 13 | it { is_expected.to allow_value('1').for(:environment_value_is_regex) } 14 | it { is_expected.to allow_value(true).for(:environment_value_is_regex) } 15 | it { is_expected.to allow_value(false).for(:environment_value_is_regex) } 16 | 17 | it { is_expected.to allow_value('0').for(:environment_value_is_case_sensitive) } 18 | it { is_expected.to allow_value('1').for(:environment_value_is_case_sensitive) } 19 | it { is_expected.to allow_value(true).for(:environment_value_is_case_sensitive) } 20 | it { is_expected.to allow_value(false).for(:environment_value_is_case_sensitive) } 21 | 22 | it 'should not allow an invalid regex' do 23 | rule = build(:request_environment_rule_regex, :environment_value => '[') 24 | 25 | rule.validate 26 | expect(rule.errors[:environment_value]).to eq(['is an invalid regular expression']) 27 | end 28 | 29 | it "should know if it's matched for a non-regex value" do 30 | subject.matches?({'SERVER_NAME' => 'example.com'}).should be_truthy 31 | subject.matches?({'HTTP_HOST' => 'www.example.com'}).should be_falsey 32 | subject.matches?({'SERVER_NAME' => 'example.ca'}).should be_falsey 33 | end 34 | 35 | context 'with a case sensitive regex value' do 36 | subject { create(:request_environment_rule_regex) } 37 | 38 | it "should know if it's matched" do 39 | expect(subject.matches?({'QUERY_STRING' => 'something=value'})).to be_truthy 40 | expect(subject.matches?({'QUERY_STRING' => 'q=search&something=value'})).to be_truthy 41 | expect(subject.matches?({'QUERY_STRING' => 'q=search&something=VALUE'})).to be_falsey 42 | expect(subject.matches?({'QUERY_STRING' => 'q=search&something=bogus'})).to be_falsey 43 | expect(subject.matches?({'QUERY_STRING' => 'q=search'})).to be_falsey 44 | expect(subject.matches?({'SERVER_NAME' => 'example.ca'})).to be_falsey 45 | end 46 | end 47 | 48 | context 'with a case insensitve regex value' do 49 | subject { create(:request_environment_rule_regex, :environment_value_is_case_sensitive => false) } 50 | 51 | it "should know if it's matched" do 52 | expect(subject.matches?({'QUERY_STRING' => 'something=value'})).to be_truthy 53 | expect(subject.matches?({'QUERY_STRING' => 'q=search&something=value'})).to be_truthy 54 | expect(subject.matches?({'QUERY_STRING' => 'q=search&something=VALUE'})).to be_truthy 55 | expect(subject.matches?({'QUERY_STRING' => 'q=search&something=bogus'})).to be_falsey 56 | expect(subject.matches?({'QUERY_STRING' => 'q=search'})).to be_falsey 57 | expect(subject.matches?({'SERVER_NAME' => 'example.ca'})).to be_falsey 58 | end 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift(File.dirname(__FILE__)) 2 | ENV['RAILS_ENV'] ||= 'test' 3 | require 'simplecov' 4 | require 'coveralls' 5 | Coveralls.wear! 'rails' 6 | 7 | require File.expand_path("../dummy/config/environment.rb", __FILE__) 8 | require 'rspec/rails' 9 | require 'shoulda-matchers' 10 | require 'capybara/rails' 11 | require 'capybara/rspec' 12 | require 'database_cleaner' 13 | require 'factory_bot_rails' 14 | require 'pry' 15 | 16 | Rails.backtrace_cleaner.remove_silencers! 17 | 18 | DatabaseCleaner.strategy = :truncation 19 | 20 | RSpec.configure do |config| 21 | config.include FactoryBot::Syntax::Methods 22 | 23 | config.mock_with :rspec 24 | config.use_transactional_fixtures = true 25 | config.infer_base_class_for_anonymous_controllers = false 26 | 27 | config.after(:each, :type => :feature) do 28 | DatabaseCleaner.clean_with :truncation, except: %w(ar_internal_metadata) 29 | Capybara.reset_sessions! # Forget the (simulated) browser state 30 | Capybara.use_default_driver # Revert Capybara.current_driver to Capybara.default_driver 31 | end 32 | 33 | # rspec-rails 3 will no longer automatically infer an example group's spec type 34 | # from the file location. You can explicitly opt-in to the feature using this 35 | # config option. 36 | # To explicitly tag specs without using automatic inference, set the `:type` 37 | # metadata manually: 38 | # 39 | # describe ThingsController, :type => :controller do 40 | # # Equivalent to being in spec/controllers 41 | # end 42 | config.infer_spec_type_from_file_location! 43 | end 44 | 45 | Shoulda::Matchers.configure do |config| 46 | config.integrate do |with| 47 | with.test_framework :rspec 48 | with.library :rails 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /tasks/performance.rake: -------------------------------------------------------------------------------- 1 | namespace :performance do 2 | desc "Test the performance of redirector (2005 records; 5 matches too evaluate the env against)" 3 | task :benchmark do 4 | require File.expand_path("../../spec/dummy/config/environment.rb", __FILE__) 5 | 6 | ActiveRecord::Base.transaction do 7 | base_regex = "something/with_[A-Za-z0-9_]+/" 8 | base_regex_attributes = { 9 | :active => true, 10 | :source_is_regex => true, 11 | :source_is_case_sensitive => true, 12 | :destination => 'http://www.example.com/products/1' 13 | } 14 | RedirectRule.create!(base_regex_attributes.merge(:source => "#{base_regex}?")) 15 | 1000.times do |i| 16 | number_of_extras = i.modulo(5) + 1 17 | regex = "#{base_regex}#{"(bogus|bonus|123456|some_other_path)/"*number_of_extras}#{i}" 18 | RedirectRule.create!(base_regex_attributes.merge(:source => regex)) 19 | end 20 | 21 | base_path = "/some/basic/path/to/" 22 | base_string_attributes = { 23 | :active => true, 24 | :source_is_regex => false, 25 | :destination => 'http://www.example.com/products/1' 26 | } 27 | 1000.times do |i| 28 | RedirectRule.create!(base_string_attributes.merge(:source => "#{base_path}#{i}")) 29 | end 30 | 31 | base_real_regex_matches = "my_real_match/to/something/" 32 | # First match 33 | rule1 = RedirectRule.create!(base_regex_attributes.merge(:source => "#{base_real_regex_matches}(some|value)", :destination => '/my_real_url')) 34 | rule1.request_environment_rules.create!(:environment_key_name => 'SERVER_NAME', 35 | :environment_value => 'my_domain.com', 36 | :environment_value_is_regex => false) 37 | rule1.request_environment_rules.create!(:environment_key_name => 'QUERY_STRING', 38 | :environment_value => 'other_param=(real|news_id)', 39 | :environment_value_is_regex => true) 40 | # Second match 41 | rule2 = RedirectRule.create!(base_regex_attributes.merge(:source => "#{base_real_regex_matches}[A-Za-z0-9_]+/?")) 42 | rule2.request_environment_rules.create!(:environment_key_name => 'SERVER_NAME', 43 | :environment_value => 'example.com', 44 | :environment_value_is_regex => false) 45 | rule2.request_environment_rules.create!(:environment_key_name => 'QUERY_STRING', 46 | :environment_value => 'example=(test|product_id)', 47 | :environment_value_is_regex => true) 48 | # Third match 49 | rule3 = RedirectRule.create!(base_regex_attributes.merge(:source => "#{base_real_regex_matches}[A-Za-z_]+/[A-Za-z0-9_]+")) 50 | rule3.request_environment_rules.create!(:environment_key_name => 'SERVER_NAME', 51 | :environment_value => 'example.com', 52 | :environment_value_is_regex => false) 53 | rule3.request_environment_rules.create!(:environment_key_name => 'QUERY_STRING', 54 | :environment_value => 'example=(test|product_id)', 55 | :environment_value_is_regex => true) 56 | # Fourth match 57 | rule4 = RedirectRule.create!(base_regex_attributes.merge(:source => "#{base_real_regex_matches}[A-Za-z_]+/[A-Za-z]+")) 58 | rule4.request_environment_rules.create!(:environment_key_name => 'SERVER_NAME', 59 | :environment_value => 'example.com', 60 | :environment_value_is_regex => false) 61 | rule4.request_environment_rules.create!(:environment_key_name => 'QUERY_STRING', 62 | :environment_value => 'example=(test|product_id)', 63 | :environment_value_is_regex => true) 64 | rule5 = RedirectRule.create!(base_regex_attributes.merge(:source => "#{base_real_regex_matches}(some|value)/other_value")) 65 | rule5.request_environment_rules.create!(:environment_key_name => 'SERVER_NAME', 66 | :environment_value => 'example.com', 67 | :environment_value_is_regex => false) 68 | rule5.request_environment_rules.create!(:environment_key_name => 'QUERY_STRING', 69 | :environment_value => 'example=(test|product_id)', 70 | :environment_value_is_regex => true) 71 | 72 | 73 | require 'benchmark' 74 | puts Benchmark.measure { 75 | 100.times do 76 | RedirectRule.destination_for('/start/my_real_match/to/something/value/other_value', { 77 | "SERVER_NAME" => 'my_domain.com', 78 | "QUERY_STRING" => 'other_param=news_id' 79 | }) 80 | end 81 | } 82 | 83 | raise ActiveRecord::Rollback 84 | end 85 | end 86 | end 87 | --------------------------------------------------------------------------------