rails_friendly_urls 1.0.1 → 1.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +19 -6
- data/Rakefile +3 -15
- data/lib/rails_friendly_urls.rb +14 -8
- data/lib/rails_friendly_urls/friendly_url.rb +12 -3
- data/lib/rails_friendly_urls/manager.rb +29 -2
- data/lib/rails_friendly_urls/route_sets/rails3.rb +11 -50
- data/lib/rails_friendly_urls/route_sets/route_set.rb +97 -0
- data/lib/rails_friendly_urls/urls/rails4_0.rb +23 -16
- data/lib/rails_friendly_urls/urls/rails4_2.rb +17 -11
- data/lib/rails_friendly_urls/version.rb +1 -1
- data/spec/apps/rails3_2.rb +0 -1
- data/spec/apps/rails4.rb +0 -1
- data/spec/spec_helper.rb +12 -9
- metadata +20 -34
- data/lib/rails_friendly_urls/route_sets/rails4_0.rb +0 -77
- data/lib/rails_friendly_urls/route_sets/rails4_2.rb +0 -50
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ca9f0ee5bfe9a12804fe9635897beb58e89368c7
|
4
|
+
data.tar.gz: d021d64e297aeeedc0f8d790d6cd7a91be257350
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d75be862be5b35ab6a801b688e99342439a6d4d28afd8f90a373b6a57e1802b04887ef524752377b362d5e64ca923c234a08ce34f9f8786f82be44d3a1ef04bd
|
7
|
+
data.tar.gz: 18d8372f1f4c2d9c57c77e60caa820762a397aff2f2c6a9b3d2f7a391c72cdd294de58083761d38d9779b68fcafb65190c66655a86b2b07c36b6f9931df1201f
|
data/README.md
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
-
#Rails Friendly Urls Engine
|
1
|
+
#Rails Friendly Urls Engine
|
2
|
+
[![Build Status](https://travis-ci.org/calonso/rails_friendly_urls.svg?branch=master)](https://travis-ci.org/calonso/rails_friendly_urls) [![Code Climate](https://codeclimate.com/github/calonso/rails_friendly_urls/badges/gpa.svg)](https://codeclimate.com/github/calonso/rails_friendly_urls) [![Test Coverage](https://codeclimate.com/github/calonso/rails_friendly_urls/badges/coverage.svg)](https://codeclimate.com/github/calonso/rails_friendly_urls/coverage) [![calonso/rails_friendly_urls API Documentation](https://www.omniref.com/github/calonso/rails_friendly_urls.png)](https://www.omniref.com/github/calonso/rails_friendly_urls)
|
2
3
|
|
3
|
-
Rails Gem to easily configure any url as a friendlier one.
|
4
|
+
Rails Gem to easily configure any url as a friendlier one.
|
4
5
|
|
5
6
|
##Features
|
6
7
|
|
7
|
-
* Allows customisation of **ABSOLUTELY** any url into a friendlier one.
|
8
|
+
* Allows customisation of **ABSOLUTELY** any url into a SEO friendlier one.
|
8
9
|
* Takes care of the parameters you defined in your original route and will pass them into the controller when the friendly url is invoked.
|
9
10
|
* Takes care of named routes and both url and path helpers so that there's no need to change a single line of code when adding a new friendly url.
|
10
11
|
* When a friendly URL is defined to substitute another one. The non-friendly one is automatically configured to redirect to the friendly path so that you're not penalised by search engines.
|
@@ -14,12 +15,14 @@ Rails Gem to easily configure any url as a friendlier one.
|
|
14
15
|
|
15
16
|
You can see the gem running live in the following url: [https://rails-friendly-urls-test.herokuapp.com/](https://rails-friendly-urls-test.herokuapp.com/)
|
16
17
|
|
18
|
+
The source code for this example project is available here: [https://github.com/calonso/rails_friendly_urls_test](https://github.com/calonso/rails_friendly_urls_test)
|
19
|
+
|
17
20
|
##Installation
|
18
21
|
|
19
22
|
Installing this gem only requires you to add the following line to your `Gemfile`
|
20
23
|
|
21
24
|
```ruby
|
22
|
-
gem 'rails_friendly_urls'
|
25
|
+
gem 'rails_friendly_urls'
|
23
26
|
```
|
24
27
|
|
25
28
|
Run
|
@@ -33,7 +36,7 @@ $ rails generate rails_friendly_urls:install
|
|
33
36
|
|
34
37
|
Here I detail you the steps that I followed to set up the friendly urls engine in the example application, so most of them should be the same for you, some others slightly different, but don't worry, you'll see appropriated explanations while reading this steps.
|
35
38
|
|
36
|
-
###1. Friendly URLs Storage
|
39
|
+
###1. Friendly URLs Storage
|
37
40
|
|
38
41
|
First of all we need to decide our urls storage technology, in my case I decided to use a standard activerecord rails model, but I guess that a YAML file could do the job as well or any other persistence technology.
|
39
42
|
|
@@ -57,7 +60,7 @@ In my example project this is the final implementation:
|
|
57
60
|
|
58
61
|
```
|
59
62
|
# FriendlyUrls Manager contents
|
60
|
-
class RailsFriendlyUrls::Manager
|
63
|
+
class RailsFriendlyUrls::Manager
|
61
64
|
def self.urls
|
62
65
|
::FriendlyUrl.all
|
63
66
|
end
|
@@ -74,3 +77,13 @@ As part of the installation process, a new line is inserted on top of the `route
|
|
74
77
|
|
75
78
|
* At the moment, only GET requests are supported.
|
76
79
|
* At the moment, the rails application has to be restarted for the new urls to start working.
|
80
|
+
|
81
|
+
## Contributing
|
82
|
+
|
83
|
+
1. Fork it ( https://github.com/calonso/rails_friendly_urls/fork )
|
84
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
85
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
86
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
87
|
+
5. Create a new Pull Request
|
88
|
+
|
89
|
+
Released under the MIT-LICENSE.
|
data/Rakefile
CHANGED
@@ -1,19 +1,7 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "bundler/setup"
|
1
3
|
require 'bundler'
|
2
|
-
|
3
|
-
Bundler.setup
|
4
|
-
Bundler.require :default
|
5
|
-
|
6
4
|
require 'appraisal'
|
7
|
-
require 'rdoc/task'
|
8
|
-
|
9
|
-
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
-
rdoc.rdoc_dir = 'rdoc'
|
11
|
-
rdoc.title = 'RailsFriendlyUrls'
|
12
|
-
rdoc.options << '--line-numbers'
|
13
|
-
rdoc.rdoc_files.include('README.rdoc')
|
14
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
-
end
|
16
|
-
|
17
5
|
|
18
6
|
require 'rspec/core/rake_task'
|
19
7
|
|
@@ -22,5 +10,5 @@ RSpec::Core::RakeTask.new(:spec)
|
|
22
10
|
task :default => :spec
|
23
11
|
|
24
12
|
if !ENV["APPRAISAL_INITIALIZED"] && !ENV["TRAVIS"]
|
25
|
-
task default
|
13
|
+
task :default => :appraisal
|
26
14
|
end
|
data/lib/rails_friendly_urls.rb
CHANGED
@@ -1,9 +1,17 @@
|
|
1
|
-
|
2
1
|
require 'singleton'
|
3
2
|
require 'rails'
|
4
3
|
|
4
|
+
#
|
5
|
+
# Base gem's module
|
6
|
+
#
|
7
|
+
# @author Carlos Alonso
|
8
|
+
#
|
5
9
|
module RailsFriendlyUrls
|
6
10
|
|
11
|
+
#
|
12
|
+
# Method to quickly get the major and minor versions of the current Rails env
|
13
|
+
#
|
14
|
+
# @returns [String] with X.Y format with major and minor versions
|
7
15
|
def self.rails_version
|
8
16
|
"#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}"
|
9
17
|
end
|
@@ -12,17 +20,15 @@ end
|
|
12
20
|
|
13
21
|
require 'rails_friendly_urls/manager'
|
14
22
|
require 'rails_friendly_urls/friendly_url'
|
23
|
+
require 'rails_friendly_urls/route_sets/route_set'
|
15
24
|
|
16
25
|
case RailsFriendlyUrls.rails_version
|
17
26
|
when '4.2'
|
18
|
-
require 'rails_friendly_urls/route_sets/rails4_2'
|
19
27
|
require 'rails_friendly_urls/urls/rails4_2'
|
20
|
-
when '4.1'
|
21
|
-
require 'rails_friendly_urls/route_sets/rails4_0'
|
22
|
-
require 'rails_friendly_urls/urls/rails4_0'
|
23
|
-
when '4.0'
|
24
|
-
require 'rails_friendly_urls/route_sets/rails4_0'
|
28
|
+
when '4.0', '4.1'
|
25
29
|
require 'rails_friendly_urls/urls/rails4_0'
|
26
|
-
|
30
|
+
when '3.2'
|
27
31
|
require 'rails_friendly_urls/route_sets/rails3'
|
32
|
+
else
|
33
|
+
raise NotImplementedError.new "Rails Friendly URLs gem doesn't support Rails #{Rails.version}"
|
28
34
|
end
|
@@ -1,7 +1,16 @@
|
|
1
|
-
|
2
1
|
module RailsFriendlyUrls
|
2
|
+
#
|
3
|
+
# This module is to be included in the client class that represents the Friendly URL
|
4
|
+
#
|
5
|
+
# @author Carlos Alonso
|
6
|
+
#
|
3
7
|
module FriendlyUrl
|
4
|
-
|
8
|
+
#
|
9
|
+
# This method tries to identify the route contained at self.path to extract
|
10
|
+
# the destination's controller, action and other arguments and save them
|
11
|
+
# into the corresponding controller, action and defaults fields of the
|
12
|
+
# including objects.
|
13
|
+
#
|
5
14
|
def set_destination_data!
|
6
15
|
route_info = Rails.application.routes.recognize_path self.path
|
7
16
|
self.controller = route_info[:controller]
|
@@ -9,4 +18,4 @@ module RailsFriendlyUrls
|
|
9
18
|
self.defaults = route_info.reject { |k, v| [:controller, :action].include? k }
|
10
19
|
end
|
11
20
|
end
|
12
|
-
end
|
21
|
+
end
|
@@ -1,8 +1,18 @@
|
|
1
|
-
|
2
1
|
module RailsFriendlyUrls
|
2
|
+
#
|
3
|
+
# This class is responsible for orchestrating the whole gem's functions.
|
4
|
+
#
|
5
|
+
# @author Carlos Alonso
|
6
|
+
#
|
3
7
|
class Manager
|
8
|
+
# It is designed to be a Singleton, only one instance will run per process.
|
4
9
|
include Singleton
|
5
10
|
|
11
|
+
#
|
12
|
+
# Injects the defined urls into the given RouteSet. This method should be invoked
|
13
|
+
# first thing in the routes.rb block
|
14
|
+
#
|
15
|
+
# @param [ActionDispatch::Routing::RouteSet] rails' current RouteSet.
|
6
16
|
def self.inject_urls(mapper)
|
7
17
|
list = self.urls || []
|
8
18
|
Rails.logger.warn "Injecting empty Friendly URLs List!!" if list.empty?
|
@@ -12,17 +22,34 @@ module RailsFriendlyUrls
|
|
12
22
|
end
|
13
23
|
end
|
14
24
|
|
25
|
+
#
|
26
|
+
# Invokes Rails' routes reload. Useful to reload the routes after
|
27
|
+
# modifying the list of SEO Friendly defined ones without having to
|
28
|
+
# restart the application server.
|
29
|
+
#
|
15
30
|
def self.apply_changes!
|
16
31
|
Rails.application.reload_routes!
|
17
32
|
end
|
18
33
|
|
34
|
+
#
|
35
|
+
# This method is used in Rails' URL Helpers to return the corresponding
|
36
|
+
# SEO Friendly URL instead of the default one.
|
37
|
+
#
|
38
|
+
# @param [String] The path we want the URL for.
|
39
|
+
# @returns [String] The SEO Friendly Slug for the required path.
|
19
40
|
def self.url_for(path)
|
20
41
|
self.instance.friendly path
|
21
42
|
end
|
22
43
|
|
44
|
+
#
|
45
|
+
# INTERNAL: Searches the list of SEO Friendly defined substitutions for
|
46
|
+
# the corresponding to the given path
|
47
|
+
#
|
48
|
+
# @param [String] The path we want the substitution for.
|
49
|
+
# @returns [String] The SEO Friendly Slugh for the required path.
|
23
50
|
def friendly(path)
|
24
51
|
@all_friendly ||= Hash[*RailsFriendlyUrls::Manager.urls.map { |f_url| [f_url.path, f_url.slug] }.flatten]
|
25
52
|
@all_friendly[path] || path
|
26
53
|
end
|
27
54
|
end
|
28
|
-
end
|
55
|
+
end
|
@@ -1,7 +1,16 @@
|
|
1
|
-
|
2
1
|
module ActionDispatch
|
3
2
|
module Routing
|
3
|
+
#
|
4
|
+
# Monkey Patched Rails' class ActionDispatch::Routing::RouteSet.
|
5
|
+
#
|
6
|
+
# @author Carlos Alonso
|
7
|
+
#
|
4
8
|
class RouteSet
|
9
|
+
#
|
10
|
+
# Monkey Patched Rails' method: Includes a call to RailsFriendlyUrls::Manager.url_for
|
11
|
+
# when the Rails' URL Helper is building a url for a path to use the
|
12
|
+
# configured SEO Friendly substutition if any.
|
13
|
+
#
|
5
14
|
def url_for(options = {})
|
6
15
|
finalize!
|
7
16
|
options = (options || {}).reverse_merge!(default_url_options)
|
@@ -21,7 +30,7 @@ module ActionDispatch
|
|
21
30
|
path << path_addition
|
22
31
|
params.merge!(options[:params] || {})
|
23
32
|
|
24
|
-
path =
|
33
|
+
path = RailsFriendlyUrls::Manager.url_for path
|
25
34
|
|
26
35
|
ActionDispatch::Http::URL.url_for(options.merge!({
|
27
36
|
:path => path,
|
@@ -30,54 +39,6 @@ module ActionDispatch
|
|
30
39
|
:password => password
|
31
40
|
}))
|
32
41
|
end
|
33
|
-
|
34
|
-
def friendly(path)
|
35
|
-
@all_friendly ||= Hash[*RailsFriendlyUrls::Manager.urls.map { |f_url| [f_url.path, f_url.slug] }.flatten]
|
36
|
-
@all_friendly[path]
|
37
|
-
end
|
38
|
-
|
39
|
-
def recognize_path(path, environment = {})
|
40
|
-
method = (environment[:method] || "GET").to_s.upcase
|
41
|
-
path = Journey::Router::Utils.normalize_path(path) unless path =~ %r{://}
|
42
|
-
extras = environment[:extras] || {}
|
43
|
-
|
44
|
-
begin
|
45
|
-
env = Rack::MockRequest.env_for(path, {:method => method})
|
46
|
-
rescue URI::InvalidURIError => e
|
47
|
-
raise ActionController::RoutingError, e.message
|
48
|
-
end
|
49
|
-
|
50
|
-
req = @request_class.new(env)
|
51
|
-
@router.recognize(req) do |route, _matches, params|
|
52
|
-
params.merge!(extras)
|
53
|
-
params.merge!(req.parameters.symbolize_keys)
|
54
|
-
params.each do |key, value|
|
55
|
-
if value.is_a?(String)
|
56
|
-
value = value.dup.force_encoding(Encoding::BINARY)
|
57
|
-
params[key] = URI.parser.unescape(value)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
old_params = env[::ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]
|
61
|
-
env[::ActionDispatch::Routing::RouteSet::PARAMETERS_KEY] = (old_params || {}).merge(params)
|
62
|
-
dispatcher = route.app
|
63
|
-
while dispatcher.is_a?(Mapper::Constraints) && dispatcher.matches?(env) do
|
64
|
-
dispatcher = dispatcher.app
|
65
|
-
end
|
66
|
-
|
67
|
-
if dispatcher.is_a?(Dispatcher)
|
68
|
-
if dispatcher.controller(params, false)
|
69
|
-
dispatcher.prepare_params!(params)
|
70
|
-
return params
|
71
|
-
else
|
72
|
-
raise ActionController::RoutingError, "A route matches #{path.inspect}, but references missing controller: #{params[:controller].camelize}Controller"
|
73
|
-
end
|
74
|
-
elsif dispatcher.is_a?(Redirect)
|
75
|
-
return { status: 301, path: dispatcher.block.call({}, nil) }
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
raise ActionController::RoutingError, "No route matches #{path.inspect}"
|
80
|
-
end
|
81
42
|
end
|
82
43
|
end
|
83
44
|
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module ActionDispatch
|
2
|
+
module Routing
|
3
|
+
#
|
4
|
+
# Monkey Patched Rails' class ActionDispatch::Routing::RouteSet.
|
5
|
+
#
|
6
|
+
# @author Carlos Alonso
|
7
|
+
#
|
8
|
+
class RouteSet
|
9
|
+
#
|
10
|
+
# Monkey Patched Rails' method to recognize redirections as well as, for some
|
11
|
+
# reason, the original Rails' method doesn't.
|
12
|
+
#
|
13
|
+
def recognize_path(path, environment = {})
|
14
|
+
method = (environment[:method] || "GET").to_s.upcase
|
15
|
+
path = Journey::Router::Utils.normalize_path(path) unless path =~ %r{://}
|
16
|
+
extras = environment[:extras] || {}
|
17
|
+
|
18
|
+
begin
|
19
|
+
env = Rack::MockRequest.env_for(path, {:method => method})
|
20
|
+
rescue URI::InvalidURIError => e
|
21
|
+
raise ActionController::RoutingError, e.message
|
22
|
+
end
|
23
|
+
|
24
|
+
req = @request_class.new(env)
|
25
|
+
@router.recognize(req) do |route, _matches, params|
|
26
|
+
params = _matches if params.nil?
|
27
|
+
params.merge!(extras)
|
28
|
+
params.merge!(req.parameters.symbolize_keys)
|
29
|
+
params.each do |key, value|
|
30
|
+
if value.is_a?(String)
|
31
|
+
value = value.dup.force_encoding(Encoding::BINARY)
|
32
|
+
params[key] = URI.parser.unescape(value)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
old_params = env[params_key]
|
37
|
+
env[params_key] = (old_params || {}).merge(params)
|
38
|
+
dispatcher = route.app
|
39
|
+
while dispatcher.is_a?(Mapper::Constraints) && dispatcher.matches?(env) do
|
40
|
+
dispatcher = dispatcher.app
|
41
|
+
end
|
42
|
+
|
43
|
+
if dispatcher.is_a?(Dispatcher)
|
44
|
+
if dispatcher.controller(params, false)
|
45
|
+
dispatcher.prepare_params!(params)
|
46
|
+
return params
|
47
|
+
else
|
48
|
+
raise ActionController::RoutingError, "A route matches #{path.inspect}, but references missing controller: #{params[:controller].camelize}Controller"
|
49
|
+
end
|
50
|
+
elsif dispatcher.is_a?(redirect_class)
|
51
|
+
return { status: 301, path: path_from_dispatcher(dispatcher) }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
raise ActionController::RoutingError, "No route matches #{path.inspect}"
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
#
|
61
|
+
# INTERNAL: Helps deciding which module take the PARAMETERS_KEY constant
|
62
|
+
# from. This constant was moved in Rails 4.2 from one to another and
|
63
|
+
# using this method here allows us to reuse this file for all Rails 4.x
|
64
|
+
#
|
65
|
+
def params_key
|
66
|
+
defined?(::ActionDispatch::Http::Parameters::PARAMETERS_KEY) ?
|
67
|
+
::ActionDispatch::Http::Parameters::PARAMETERS_KEY :
|
68
|
+
::ActionDispatch::Routing::RouteSet::PARAMETERS_KEY
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
# INTERNAL: Helps reusing code by deciding which class to consider
|
73
|
+
# as the redirection depending on the Rails version running.
|
74
|
+
#
|
75
|
+
# @returns [ActionDispatch::Routing::Redirect] or [ActionDispatch::Routing::PathRedirect]
|
76
|
+
def redirect_class
|
77
|
+
Rails::VERSION::MAJOR == 3 ? Redirect : PathRedirect
|
78
|
+
end
|
79
|
+
|
80
|
+
#
|
81
|
+
# INTERNAL: Helps reusing code by obtaining the path from the Rails'
|
82
|
+
# ActionDispatch::Routing::Dispatcher depending on the Rails version
|
83
|
+
# running.
|
84
|
+
#
|
85
|
+
# @param [ActionDispatch::Routing::Dispatcher] in use.
|
86
|
+
# @return [String] the destination path of the redirection.
|
87
|
+
def path_from_dispatcher(dispatcher)
|
88
|
+
if Rails::VERSION::MAJOR == 3
|
89
|
+
dispatcher.block.call({}, nil)
|
90
|
+
else
|
91
|
+
dispatcher.block
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
@@ -1,28 +1,35 @@
|
|
1
|
-
|
2
1
|
module ActionDispatch
|
3
2
|
module Http
|
3
|
+
#
|
4
|
+
# Monkey Patched Rails' module ActionDispatch::Http::URL
|
5
|
+
#
|
6
|
+
# @author Carlos Alonso
|
7
|
+
#
|
4
8
|
module URL
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
9
|
+
#
|
10
|
+
# Monkey Patched Rails' method: Includes a call to RailsFriendlyUrls::Manager.url_for
|
11
|
+
# when the Rails' URL Helper is building a url for a path to use the
|
12
|
+
# configured SEO Friendly substutition if any.
|
13
|
+
#
|
14
|
+
def self.url_for(options = {})
|
15
|
+
options = options.dup
|
16
|
+
path = options.delete(:script_name).to_s.chomp("/")
|
17
|
+
path << options.delete(:path).to_s
|
10
18
|
|
11
|
-
|
19
|
+
add_trailing_slash(path) if options[:trailing_slash]
|
12
20
|
|
13
|
-
|
14
|
-
|
21
|
+
params = options[:params].is_a?(Hash) ? options[:params] : options.slice(:params)
|
22
|
+
params.reject! { |_,v| v.to_param.nil? }
|
15
23
|
|
16
|
-
|
24
|
+
result = build_host_url(options)
|
17
25
|
|
18
|
-
|
26
|
+
path = RailsFriendlyUrls::Manager.url_for path
|
19
27
|
|
20
|
-
|
28
|
+
result << path
|
21
29
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
end
|
30
|
+
result << "?#{params.to_query}" unless params.empty?
|
31
|
+
result << "##{Journey::Router::Utils.escape_fragment(options[:anchor].to_param.to_s)}" if options[:anchor]
|
32
|
+
result
|
26
33
|
end
|
27
34
|
end
|
28
35
|
end
|
@@ -1,19 +1,25 @@
|
|
1
|
-
|
2
1
|
module ActionDispatch
|
3
2
|
module Http
|
3
|
+
#
|
4
|
+
# Monkey Patched Rails' module ActionDispatch::Http::URL
|
5
|
+
#
|
6
|
+
# @author Carlos Alonso
|
7
|
+
#
|
4
8
|
module URL
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
9
|
+
#
|
10
|
+
# Monkey Patched Rails' method: Includes a call to RailsFriendlyUrls::Manager.url_for
|
11
|
+
# when the Rails' URL Helper is building a url for a path to use the
|
12
|
+
# configured SEO Friendly substutition if any.
|
13
|
+
#
|
14
|
+
def self.path_for(options)
|
15
|
+
path = options[:script_name].to_s.chomp("/")
|
16
|
+
path << options[:path] if options.key?(:path)
|
10
17
|
|
11
|
-
|
12
|
-
|
13
|
-
|
18
|
+
add_trailing_slash(path) if options[:trailing_slash]
|
19
|
+
add_params(path, options[:params]) if options.key?(:params)
|
20
|
+
add_anchor(path, options[:anchor]) if options.key?(:anchor)
|
14
21
|
|
15
|
-
|
16
|
-
end
|
22
|
+
RailsFriendlyUrls::Manager.url_for path
|
17
23
|
end
|
18
24
|
end
|
19
25
|
end
|
data/spec/apps/rails3_2.rb
CHANGED
data/spec/apps/rails4.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
# Configure Rails Environment
|
2
|
-
|
3
|
-
|
4
|
-
Bundler.require :development
|
2
|
+
require "codeclimate-test-reporter"
|
3
|
+
CodeClimate::TestReporter.start
|
5
4
|
|
6
|
-
|
5
|
+
Bundler.setup
|
7
6
|
|
8
7
|
ENV["RAILS_ENV"] = "test"
|
9
8
|
|
10
|
-
|
9
|
+
require 'rails'
|
10
|
+
|
11
|
+
case "#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}"
|
11
12
|
when '3.2'
|
12
13
|
ENV['DATABASE_URL'] = 'sqlite3://localhost/:memory:'
|
13
14
|
require 'apps/rails3_2'
|
@@ -24,9 +25,11 @@ else
|
|
24
25
|
raise NotImplementedError.new "Rails Friendly URLs gem doesn't support Rails #{Rails.version}"
|
25
26
|
end
|
26
27
|
|
27
|
-
require
|
28
|
+
Bundler.require :default
|
29
|
+
Bundler.require :development
|
28
30
|
|
29
|
-
|
31
|
+
require 'rspec/rails'
|
32
|
+
require 'rails_friendly_urls'
|
30
33
|
|
31
34
|
# Load support files
|
32
35
|
Dir["#{File.dirname(__FILE__)}/support/*.rb"].each { |f| require f }
|
@@ -44,5 +47,5 @@ RSpec.configure do |config|
|
|
44
47
|
# order dependency and want to debug it, you can fix the order by providing
|
45
48
|
# the seed, which is printed after each run.
|
46
49
|
# --seed 1234
|
47
|
-
config.order =
|
48
|
-
end
|
50
|
+
config.order = :random
|
51
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails_friendly_urls
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Carlos Alonso
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-
|
12
|
+
date: 2015-05-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -25,76 +25,62 @@ dependencies:
|
|
25
25
|
- - ">="
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '3.2'
|
28
|
-
- !ruby/object:Gem::Dependency
|
29
|
-
name: appraisal
|
30
|
-
requirement: !ruby/object:Gem::Requirement
|
31
|
-
requirements:
|
32
|
-
- - ">="
|
33
|
-
- !ruby/object:Gem::Version
|
34
|
-
version: '0'
|
35
|
-
type: :development
|
36
|
-
prerelease: false
|
37
|
-
version_requirements: !ruby/object:Gem::Requirement
|
38
|
-
requirements:
|
39
|
-
- - ">="
|
40
|
-
- !ruby/object:Gem::Version
|
41
|
-
version: '0'
|
42
28
|
- !ruby/object:Gem::Dependency
|
43
29
|
name: sqlite3
|
44
30
|
requirement: !ruby/object:Gem::Requirement
|
45
31
|
requirements:
|
46
|
-
- - "
|
32
|
+
- - "~>"
|
47
33
|
- !ruby/object:Gem::Version
|
48
|
-
version: '
|
34
|
+
version: '1.3'
|
49
35
|
type: :development
|
50
36
|
prerelease: false
|
51
37
|
version_requirements: !ruby/object:Gem::Requirement
|
52
38
|
requirements:
|
53
|
-
- - "
|
39
|
+
- - "~>"
|
54
40
|
- !ruby/object:Gem::Version
|
55
|
-
version: '
|
41
|
+
version: '1.3'
|
56
42
|
- !ruby/object:Gem::Dependency
|
57
|
-
name: rspec
|
43
|
+
name: rspec
|
58
44
|
requirement: !ruby/object:Gem::Requirement
|
59
45
|
requirements:
|
60
46
|
- - "~>"
|
61
47
|
- !ruby/object:Gem::Version
|
62
|
-
version: '2
|
48
|
+
version: '3.2'
|
63
49
|
type: :development
|
64
50
|
prerelease: false
|
65
51
|
version_requirements: !ruby/object:Gem::Requirement
|
66
52
|
requirements:
|
67
53
|
- - "~>"
|
68
54
|
- !ruby/object:Gem::Version
|
69
|
-
version: '2
|
55
|
+
version: '3.2'
|
70
56
|
- !ruby/object:Gem::Dependency
|
71
57
|
name: rspec-rails
|
72
58
|
requirement: !ruby/object:Gem::Requirement
|
73
59
|
requirements:
|
74
|
-
- - "
|
60
|
+
- - "~>"
|
75
61
|
- !ruby/object:Gem::Version
|
76
|
-
version: '0'
|
62
|
+
version: '3.0'
|
77
63
|
type: :development
|
78
64
|
prerelease: false
|
79
65
|
version_requirements: !ruby/object:Gem::Requirement
|
80
66
|
requirements:
|
81
|
-
- - "
|
67
|
+
- - "~>"
|
82
68
|
- !ruby/object:Gem::Version
|
83
|
-
version: '0'
|
69
|
+
version: '3.0'
|
84
70
|
- !ruby/object:Gem::Dependency
|
85
71
|
name: generator_spec
|
86
72
|
requirement: !ruby/object:Gem::Requirement
|
87
73
|
requirements:
|
88
|
-
- - "
|
74
|
+
- - "~>"
|
89
75
|
- !ruby/object:Gem::Version
|
90
|
-
version: '0'
|
76
|
+
version: '0.9'
|
91
77
|
type: :development
|
92
78
|
prerelease: false
|
93
79
|
version_requirements: !ruby/object:Gem::Requirement
|
94
80
|
requirements:
|
95
|
-
- - "
|
81
|
+
- - "~>"
|
96
82
|
- !ruby/object:Gem::Version
|
97
|
-
version: '0'
|
83
|
+
version: '0.9'
|
98
84
|
description: Rails Gem to easily configure any url as a friendlier one.
|
99
85
|
email: info@mrcalonso.com
|
100
86
|
executables: []
|
@@ -109,8 +95,7 @@ files:
|
|
109
95
|
- lib/rails_friendly_urls/friendly_url.rb
|
110
96
|
- lib/rails_friendly_urls/manager.rb
|
111
97
|
- lib/rails_friendly_urls/route_sets/rails3.rb
|
112
|
-
- lib/rails_friendly_urls/route_sets/
|
113
|
-
- lib/rails_friendly_urls/route_sets/rails4_2.rb
|
98
|
+
- lib/rails_friendly_urls/route_sets/route_set.rb
|
114
99
|
- lib/rails_friendly_urls/urls/rails4_0.rb
|
115
100
|
- lib/rails_friendly_urls/urls/rails4_2.rb
|
116
101
|
- lib/rails_friendly_urls/version.rb
|
@@ -145,7 +130,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
145
130
|
version: '0'
|
146
131
|
requirements: []
|
147
132
|
rubyforge_project:
|
148
|
-
rubygems_version: 2.
|
133
|
+
rubygems_version: 2.2.2
|
149
134
|
signing_key:
|
150
135
|
specification_version: 4
|
151
136
|
summary: This is a Rails gem that allows to configure friendly urls for any url in
|
@@ -162,3 +147,4 @@ test_files:
|
|
162
147
|
- spec/support/routes/rails3.rb
|
163
148
|
- spec/support/routes/rails4.rb
|
164
149
|
- spec/support/routes.rb
|
150
|
+
has_rdoc:
|
@@ -1,77 +0,0 @@
|
|
1
|
-
|
2
|
-
module ActionDispatch
|
3
|
-
module Routing
|
4
|
-
class RouteSet
|
5
|
-
def url_for(options = {})
|
6
|
-
finalize!
|
7
|
-
options = (options || {}).reverse_merge!(default_url_options)
|
8
|
-
|
9
|
-
handle_positional_args(options)
|
10
|
-
|
11
|
-
user, password = extract_authentication(options)
|
12
|
-
path_segments = options.delete(:_path_segments)
|
13
|
-
script_name = options.delete(:script_name)
|
14
|
-
|
15
|
-
path = (script_name.blank? ? _generate_prefix(options) : script_name.chomp('/')).to_s
|
16
|
-
|
17
|
-
path_options = options.except(*RESERVED_OPTIONS)
|
18
|
-
path_options = yield(path_options) if block_given?
|
19
|
-
|
20
|
-
path_addition, params = generate(path_options, path_segments || {})
|
21
|
-
path << path_addition
|
22
|
-
params.merge!(options[:params] || {})
|
23
|
-
|
24
|
-
ActionDispatch::Http::URL.url_for(options.merge!({
|
25
|
-
:path => path,
|
26
|
-
:params => params,
|
27
|
-
:user => user,
|
28
|
-
:password => password
|
29
|
-
}))
|
30
|
-
end
|
31
|
-
|
32
|
-
def recognize_path(path, environment = {})
|
33
|
-
method = (environment[:method] || "GET").to_s.upcase
|
34
|
-
path = Journey::Router::Utils.normalize_path(path) unless path =~ %r{://}
|
35
|
-
extras = environment[:extras] || {}
|
36
|
-
|
37
|
-
begin
|
38
|
-
env = Rack::MockRequest.env_for(path, {:method => method})
|
39
|
-
rescue URI::InvalidURIError => e
|
40
|
-
raise ActionController::RoutingError, e.message
|
41
|
-
end
|
42
|
-
|
43
|
-
req = @request_class.new(env)
|
44
|
-
@router.recognize(req) do |route, _matches, params|
|
45
|
-
params.merge!(extras)
|
46
|
-
params.merge!(req.parameters.symbolize_keys)
|
47
|
-
params.each do |key, value|
|
48
|
-
if value.is_a?(String)
|
49
|
-
value = value.dup.force_encoding(Encoding::BINARY)
|
50
|
-
params[key] = URI.parser.unescape(value)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
old_params = env[::ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]
|
54
|
-
env[::ActionDispatch::Routing::RouteSet::PARAMETERS_KEY] = (old_params || {}).merge(params)
|
55
|
-
dispatcher = route.app
|
56
|
-
while dispatcher.is_a?(Mapper::Constraints) && dispatcher.matches?(env) do
|
57
|
-
dispatcher = dispatcher.app
|
58
|
-
end
|
59
|
-
|
60
|
-
if dispatcher.is_a?(Dispatcher)
|
61
|
-
if dispatcher.controller(params, false)
|
62
|
-
dispatcher.prepare_params!(params)
|
63
|
-
return params
|
64
|
-
else
|
65
|
-
raise ActionController::RoutingError, "A route matches #{path.inspect}, but references missing controller: #{params[:controller].camelize}Controller"
|
66
|
-
end
|
67
|
-
elsif dispatcher.is_a?(PathRedirect)
|
68
|
-
return { :status => dispatcher.status, :path => dispatcher.block }
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
raise ActionController::RoutingError, "No route matches #{path.inspect}"
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
@@ -1,50 +0,0 @@
|
|
1
|
-
|
2
|
-
module ActionDispatch
|
3
|
-
module Routing
|
4
|
-
class RouteSet
|
5
|
-
def recognize_path(path, environment = {})
|
6
|
-
method = (environment[:method] || "GET").to_s.upcase
|
7
|
-
path = Journey::Router::Utils.normalize_path(path) unless path =~ %r{://}
|
8
|
-
extras = environment[:extras] || {}
|
9
|
-
|
10
|
-
begin
|
11
|
-
env = Rack::MockRequest.env_for(path, {:method => method})
|
12
|
-
rescue URI::InvalidURIError => e
|
13
|
-
raise ActionController::RoutingError, e.message
|
14
|
-
end
|
15
|
-
|
16
|
-
req = @request_class.new(env)
|
17
|
-
@router.recognize(req) do |route, params|
|
18
|
-
params.merge!(extras)
|
19
|
-
params.merge!(req.parameters.symbolize_keys)
|
20
|
-
params.each do |key, value|
|
21
|
-
if value.is_a?(String)
|
22
|
-
value = value.dup.force_encoding(Encoding::BINARY)
|
23
|
-
params[key] = URI.parser.unescape(value)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
old_params = env[::ActionDispatch::Http::Parameters::PARAMETERS_KEY]
|
27
|
-
env[::ActionDispatch::Http::Parameters::PARAMETERS_KEY] = (old_params || {}).merge(params)
|
28
|
-
dispatcher = route.app
|
29
|
-
while dispatcher.is_a?(Mapper::Constraints) && dispatcher.matches?(env) do
|
30
|
-
dispatcher = dispatcher.app
|
31
|
-
end
|
32
|
-
|
33
|
-
if dispatcher.is_a?(Dispatcher)
|
34
|
-
if dispatcher.controller(params, false)
|
35
|
-
dispatcher.prepare_params!(params)
|
36
|
-
return params
|
37
|
-
else
|
38
|
-
raise ActionController::RoutingError, "A route matches #{path.inspect}, but references missing controller: #{params[:controller].camelize}Controller"
|
39
|
-
end
|
40
|
-
elsif dispatcher.is_a?(PathRedirect)
|
41
|
-
return { :status => dispatcher.status, :path => dispatcher.block }
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
raise ActionController::RoutingError, "No route matches #{path.inspect}"
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|