rails_friendly_urls 0.1.2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +6 -19
- data/Rakefile +15 -3
- data/lib/rails_friendly_urls.rb +8 -14
- data/lib/rails_friendly_urls/friendly_url.rb +3 -12
- data/lib/rails_friendly_urls/manager.rb +2 -29
- data/lib/rails_friendly_urls/route_sets/rails3.rb +50 -11
- data/lib/rails_friendly_urls/route_sets/rails4_0.rb +77 -0
- data/lib/rails_friendly_urls/route_sets/rails4_2.rb +50 -0
- data/lib/rails_friendly_urls/urls/rails4_0.rb +16 -23
- data/lib/rails_friendly_urls/urls/rails4_2.rb +11 -17
- data/lib/rails_friendly_urls/version.rb +1 -1
- data/spec/apps/rails3_2.rb +1 -0
- data/spec/apps/rails4.rb +1 -0
- data/spec/spec_helper.rb +9 -12
- metadata +41 -29
- data/lib/rails_friendly_urls/route_sets/route_set.rb +0 -97
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b394a9ca563622084ae8afd40a305da3a51ebb7f
|
4
|
+
data.tar.gz: 35c6ddf6c00c967cb0bbe54fb489939da3ea602d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f0ed8adf9d09be68841594d2c28ee524faa1c333c29e165dae2f89f2aba1104076223802a9b4b1147d71cac25ed2f6e932afde1ca717d174ee7b67ea495fa32e
|
7
|
+
data.tar.gz: c0039de9f3ce7d2248ef1348b211e0d4f2d4169a6ae0a15f76162eeaaa45a2c850ca467c1a57f1013637f710b72c00231004be123332b11580f65e797a02c5c0
|
data/README.md
CHANGED
@@ -1,11 +1,10 @@
|
|
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)
|
1
|
+
#Rails Friendly Urls Engine [![Build Status](https://travis-ci.org/calonso/rails_friendly_urls.svg?branch=master)](https://travis-ci.org/calonso/rails_friendly_urls)
|
3
2
|
|
4
|
-
Rails Gem to easily configure any url as a friendlier one.
|
3
|
+
Rails Gem to easily configure any url as a friendlier one.
|
5
4
|
|
6
5
|
##Features
|
7
6
|
|
8
|
-
* Allows customisation of **ABSOLUTELY** any url into a
|
7
|
+
* Allows customisation of **ABSOLUTELY** any url into a friendlier one.
|
9
8
|
* Takes care of the parameters you defined in your original route and will pass them into the controller when the friendly url is invoked.
|
10
9
|
* 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.
|
11
10
|
* 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.
|
@@ -15,14 +14,12 @@ Rails Gem to easily configure any url as a friendlier one.
|
|
15
14
|
|
16
15
|
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/)
|
17
16
|
|
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
|
-
|
20
17
|
##Installation
|
21
18
|
|
22
19
|
Installing this gem only requires you to add the following line to your `Gemfile`
|
23
20
|
|
24
21
|
```ruby
|
25
|
-
gem 'rails_friendly_urls'
|
22
|
+
gem 'rails_friendly_urls', git: 'https://github.com/calonso/rails_friendly_urls'
|
26
23
|
```
|
27
24
|
|
28
25
|
Run
|
@@ -36,7 +33,7 @@ $ rails generate rails_friendly_urls:install
|
|
36
33
|
|
37
34
|
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.
|
38
35
|
|
39
|
-
###1. Friendly URLs Storage
|
36
|
+
###1. Friendly URLs Storage
|
40
37
|
|
41
38
|
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.
|
42
39
|
|
@@ -60,7 +57,7 @@ In my example project this is the final implementation:
|
|
60
57
|
|
61
58
|
```
|
62
59
|
# FriendlyUrls Manager contents
|
63
|
-
class RailsFriendlyUrls::Manager
|
60
|
+
class RailsFriendlyUrls::Manager
|
64
61
|
def self.urls
|
65
62
|
::FriendlyUrl.all
|
66
63
|
end
|
@@ -77,13 +74,3 @@ As part of the installation process, a new line is inserted on top of the `route
|
|
77
74
|
|
78
75
|
* At the moment, only GET requests are supported.
|
79
76
|
* 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,7 +1,19 @@
|
|
1
|
-
require "rubygems"
|
2
|
-
require "bundler/setup"
|
3
1
|
require 'bundler'
|
2
|
+
|
3
|
+
Bundler.setup
|
4
|
+
Bundler.require :default
|
5
|
+
|
4
6
|
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
|
+
|
5
17
|
|
6
18
|
require 'rspec/core/rake_task'
|
7
19
|
|
@@ -10,5 +22,5 @@ RSpec::Core::RakeTask.new(:spec)
|
|
10
22
|
task :default => :spec
|
11
23
|
|
12
24
|
if !ENV["APPRAISAL_INITIALIZED"] && !ENV["TRAVIS"]
|
13
|
-
task :
|
25
|
+
task default: :appraisal
|
14
26
|
end
|
data/lib/rails_friendly_urls.rb
CHANGED
@@ -1,17 +1,9 @@
|
|
1
|
+
|
1
2
|
require 'singleton'
|
2
3
|
require 'rails'
|
3
4
|
|
4
|
-
#
|
5
|
-
# Base gem's module
|
6
|
-
#
|
7
|
-
# @author Carlos Alonso
|
8
|
-
#
|
9
5
|
module RailsFriendlyUrls
|
10
6
|
|
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
|
15
7
|
def self.rails_version
|
16
8
|
"#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}"
|
17
9
|
end
|
@@ -20,15 +12,17 @@ end
|
|
20
12
|
|
21
13
|
require 'rails_friendly_urls/manager'
|
22
14
|
require 'rails_friendly_urls/friendly_url'
|
23
|
-
require 'rails_friendly_urls/route_sets/route_set'
|
24
15
|
|
25
16
|
case RailsFriendlyUrls.rails_version
|
26
17
|
when '4.2'
|
18
|
+
require 'rails_friendly_urls/route_sets/rails4_2'
|
27
19
|
require 'rails_friendly_urls/urls/rails4_2'
|
28
|
-
when '4.
|
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'
|
29
25
|
require 'rails_friendly_urls/urls/rails4_0'
|
30
|
-
when '3.2'
|
31
|
-
require 'rails_friendly_urls/route_sets/rails3'
|
32
26
|
else
|
33
|
-
|
27
|
+
require 'rails_friendly_urls/route_sets/rails3'
|
34
28
|
end
|
@@ -1,16 +1,7 @@
|
|
1
|
+
|
1
2
|
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
|
-
#
|
7
3
|
module FriendlyUrl
|
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
|
-
#
|
4
|
+
|
14
5
|
def set_destination_data!
|
15
6
|
route_info = Rails.application.routes.recognize_path self.path
|
16
7
|
self.controller = route_info[:controller]
|
@@ -18,4 +9,4 @@ module RailsFriendlyUrls
|
|
18
9
|
self.defaults = route_info.reject { |k, v| [:controller, :action].include? k }
|
19
10
|
end
|
20
11
|
end
|
21
|
-
end
|
12
|
+
end
|
@@ -1,18 +1,8 @@
|
|
1
|
+
|
1
2
|
module RailsFriendlyUrls
|
2
|
-
#
|
3
|
-
# This class is responsible for orchestrating the whole gem's functions.
|
4
|
-
#
|
5
|
-
# @author Carlos Alonso
|
6
|
-
#
|
7
3
|
class Manager
|
8
|
-
# It is designed to be a Singleton, only one instance will run per process.
|
9
4
|
include Singleton
|
10
5
|
|
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.
|
16
6
|
def self.inject_urls(mapper)
|
17
7
|
list = self.urls || []
|
18
8
|
Rails.logger.warn "Injecting empty Friendly URLs List!!" if list.empty?
|
@@ -22,34 +12,17 @@ module RailsFriendlyUrls
|
|
22
12
|
end
|
23
13
|
end
|
24
14
|
|
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
|
-
#
|
30
15
|
def self.apply_changes!
|
31
16
|
Rails.application.reload_routes!
|
32
17
|
end
|
33
18
|
|
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.
|
40
19
|
def self.url_for(path)
|
41
20
|
self.instance.friendly path
|
42
21
|
end
|
43
22
|
|
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.
|
50
23
|
def friendly(path)
|
51
24
|
@all_friendly ||= Hash[*RailsFriendlyUrls::Manager.urls.map { |f_url| [f_url.path, f_url.slug] }.flatten]
|
52
25
|
@all_friendly[path] || path
|
53
26
|
end
|
54
27
|
end
|
55
|
-
end
|
28
|
+
end
|
@@ -1,16 +1,7 @@
|
|
1
|
+
|
1
2
|
module ActionDispatch
|
2
3
|
module Routing
|
3
|
-
#
|
4
|
-
# Monkey Patched Rails' class ActionDispatch::Routing::RouteSet.
|
5
|
-
#
|
6
|
-
# @author Carlos Alonso
|
7
|
-
#
|
8
4
|
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
|
-
#
|
14
5
|
def url_for(options = {})
|
15
6
|
finalize!
|
16
7
|
options = (options || {}).reverse_merge!(default_url_options)
|
@@ -30,7 +21,7 @@ module ActionDispatch
|
|
30
21
|
path << path_addition
|
31
22
|
params.merge!(options[:params] || {})
|
32
23
|
|
33
|
-
path =
|
24
|
+
path = friendly(path) || path
|
34
25
|
|
35
26
|
ActionDispatch::Http::URL.url_for(options.merge!({
|
36
27
|
:path => path,
|
@@ -39,6 +30,54 @@ module ActionDispatch
|
|
39
30
|
:password => password
|
40
31
|
}))
|
41
32
|
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
|
42
81
|
end
|
43
82
|
end
|
44
83
|
end
|
@@ -0,0 +1,77 @@
|
|
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
|
+
|
@@ -0,0 +1,50 @@
|
|
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
|
+
|
@@ -1,35 +1,28 @@
|
|
1
|
+
|
1
2
|
module ActionDispatch
|
2
3
|
module Http
|
3
|
-
#
|
4
|
-
# Monkey Patched Rails' module ActionDispatch::Http::URL
|
5
|
-
#
|
6
|
-
# @author Carlos Alonso
|
7
|
-
#
|
8
4
|
module URL
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
5
|
+
class << self
|
6
|
+
def url_for(options = {})
|
7
|
+
options = options.dup
|
8
|
+
path = options.delete(:script_name).to_s.chomp("/")
|
9
|
+
path << options.delete(:path).to_s
|
18
10
|
|
19
|
-
|
11
|
+
add_trailing_slash(path) if options[:trailing_slash]
|
20
12
|
|
21
|
-
|
22
|
-
|
13
|
+
params = options[:params].is_a?(Hash) ? options[:params] : options.slice(:params)
|
14
|
+
params.reject! { |_,v| v.to_param.nil? }
|
23
15
|
|
24
|
-
|
16
|
+
result = build_host_url(options)
|
25
17
|
|
26
|
-
|
18
|
+
path = RailsFriendlyUrls::Manager.url_for path
|
27
19
|
|
28
|
-
|
20
|
+
result << path
|
29
21
|
|
30
|
-
|
31
|
-
|
32
|
-
|
22
|
+
result << "?#{params.to_query}" unless params.empty?
|
23
|
+
result << "##{Journey::Router::Utils.escape_fragment(options[:anchor].to_param.to_s)}" if options[:anchor]
|
24
|
+
result
|
25
|
+
end
|
33
26
|
end
|
34
27
|
end
|
35
28
|
end
|
@@ -1,25 +1,19 @@
|
|
1
|
+
|
1
2
|
module ActionDispatch
|
2
3
|
module Http
|
3
|
-
#
|
4
|
-
# Monkey Patched Rails' module ActionDispatch::Http::URL
|
5
|
-
#
|
6
|
-
# @author Carlos Alonso
|
7
|
-
#
|
8
4
|
module URL
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
def self.path_for(options)
|
15
|
-
path = options[:script_name].to_s.chomp("/")
|
16
|
-
path << options[:path] if options.key?(:path)
|
5
|
+
class << self
|
6
|
+
|
7
|
+
def path_for(options)
|
8
|
+
path = options[:script_name].to_s.chomp("/")
|
9
|
+
path << options[:path] if options.key?(:path)
|
17
10
|
|
18
|
-
|
19
|
-
|
20
|
-
|
11
|
+
add_trailing_slash(path) if options[:trailing_slash]
|
12
|
+
add_params(path, options[:params]) if options.key?(:params)
|
13
|
+
add_anchor(path, options[:anchor]) if options.key?(:anchor)
|
21
14
|
|
22
|
-
|
15
|
+
RailsFriendlyUrls::Manager.url_for path
|
16
|
+
end
|
23
17
|
end
|
24
18
|
end
|
25
19
|
end
|
data/spec/apps/rails3_2.rb
CHANGED
data/spec/apps/rails4.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
# Configure Rails Environment
|
2
|
-
require "codeclimate-test-reporter"
|
3
|
-
CodeClimate::TestReporter.start
|
4
|
-
|
5
2
|
Bundler.setup
|
3
|
+
Bundler.require :default
|
4
|
+
Bundler.require :development
|
6
5
|
|
7
|
-
|
6
|
+
require 'rails_friendly_urls'
|
8
7
|
|
9
|
-
|
8
|
+
ENV["RAILS_ENV"] = "test"
|
10
9
|
|
11
|
-
case
|
10
|
+
case RailsFriendlyUrls.rails_version
|
12
11
|
when '3.2'
|
13
12
|
ENV['DATABASE_URL'] = 'sqlite3://localhost/:memory:'
|
14
13
|
require 'apps/rails3_2'
|
@@ -25,11 +24,9 @@ else
|
|
25
24
|
raise NotImplementedError.new "Rails Friendly URLs gem doesn't support Rails #{Rails.version}"
|
26
25
|
end
|
27
26
|
|
28
|
-
Bundler.require :default
|
29
|
-
Bundler.require :development
|
30
|
-
|
31
27
|
require 'rspec/rails'
|
32
|
-
|
28
|
+
|
29
|
+
Rails.backtrace_cleaner.remove_silencers!
|
33
30
|
|
34
31
|
# Load support files
|
35
32
|
Dir["#{File.dirname(__FILE__)}/support/*.rb"].each { |f| require f }
|
@@ -47,5 +44,5 @@ RSpec.configure do |config|
|
|
47
44
|
# order dependency and want to debug it, you can fix the order by providing
|
48
45
|
# the seed, which is printed after each run.
|
49
46
|
# --seed 1234
|
50
|
-
config.order =
|
51
|
-
end
|
47
|
+
config.order = "random"
|
48
|
+
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: 0.
|
4
|
+
version: 1.0.0
|
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-02-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -17,72 +17,86 @@ dependencies:
|
|
17
17
|
requirements:
|
18
18
|
- - ">="
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version: '
|
20
|
+
version: '0'
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
25
|
- - ">="
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version: '
|
27
|
+
version: '0'
|
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'
|
28
42
|
- !ruby/object:Gem::Dependency
|
29
43
|
name: sqlite3
|
30
44
|
requirement: !ruby/object:Gem::Requirement
|
31
45
|
requirements:
|
32
|
-
- - "
|
46
|
+
- - ">="
|
33
47
|
- !ruby/object:Gem::Version
|
34
|
-
version: '
|
48
|
+
version: '0'
|
35
49
|
type: :development
|
36
50
|
prerelease: false
|
37
51
|
version_requirements: !ruby/object:Gem::Requirement
|
38
52
|
requirements:
|
39
|
-
- - "
|
53
|
+
- - ">="
|
40
54
|
- !ruby/object:Gem::Version
|
41
|
-
version: '
|
55
|
+
version: '0'
|
42
56
|
- !ruby/object:Gem::Dependency
|
43
|
-
name: rspec
|
57
|
+
name: rspec-core
|
44
58
|
requirement: !ruby/object:Gem::Requirement
|
45
59
|
requirements:
|
46
60
|
- - "~>"
|
47
61
|
- !ruby/object:Gem::Version
|
48
|
-
version: '
|
62
|
+
version: '2.4'
|
49
63
|
type: :development
|
50
64
|
prerelease: false
|
51
65
|
version_requirements: !ruby/object:Gem::Requirement
|
52
66
|
requirements:
|
53
67
|
- - "~>"
|
54
68
|
- !ruby/object:Gem::Version
|
55
|
-
version: '
|
69
|
+
version: '2.4'
|
56
70
|
- !ruby/object:Gem::Dependency
|
57
71
|
name: rspec-rails
|
58
72
|
requirement: !ruby/object:Gem::Requirement
|
59
73
|
requirements:
|
60
|
-
- - "
|
74
|
+
- - ">="
|
61
75
|
- !ruby/object:Gem::Version
|
62
|
-
version: '
|
76
|
+
version: '0'
|
63
77
|
type: :development
|
64
78
|
prerelease: false
|
65
79
|
version_requirements: !ruby/object:Gem::Requirement
|
66
80
|
requirements:
|
67
|
-
- - "
|
81
|
+
- - ">="
|
68
82
|
- !ruby/object:Gem::Version
|
69
|
-
version: '
|
83
|
+
version: '0'
|
70
84
|
- !ruby/object:Gem::Dependency
|
71
85
|
name: generator_spec
|
72
86
|
requirement: !ruby/object:Gem::Requirement
|
73
87
|
requirements:
|
74
|
-
- - "
|
88
|
+
- - ">="
|
75
89
|
- !ruby/object:Gem::Version
|
76
|
-
version: '0
|
90
|
+
version: '0'
|
77
91
|
type: :development
|
78
92
|
prerelease: false
|
79
93
|
version_requirements: !ruby/object:Gem::Requirement
|
80
94
|
requirements:
|
81
|
-
- - "
|
95
|
+
- - ">="
|
82
96
|
- !ruby/object:Gem::Version
|
83
|
-
version: '0
|
84
|
-
description:
|
85
|
-
email:
|
97
|
+
version: '0'
|
98
|
+
description: Description of RailsFriendlyUrls.
|
99
|
+
email: carlos@mrcalonso.com
|
86
100
|
executables: []
|
87
101
|
extensions: []
|
88
102
|
extra_rdoc_files: []
|
@@ -95,7 +109,8 @@ files:
|
|
95
109
|
- lib/rails_friendly_urls/friendly_url.rb
|
96
110
|
- lib/rails_friendly_urls/manager.rb
|
97
111
|
- lib/rails_friendly_urls/route_sets/rails3.rb
|
98
|
-
- lib/rails_friendly_urls/route_sets/
|
112
|
+
- lib/rails_friendly_urls/route_sets/rails4_0.rb
|
113
|
+
- lib/rails_friendly_urls/route_sets/rails4_2.rb
|
99
114
|
- lib/rails_friendly_urls/urls/rails4_0.rb
|
100
115
|
- lib/rails_friendly_urls/urls/rails4_2.rb
|
101
116
|
- lib/rails_friendly_urls/version.rb
|
@@ -111,8 +126,7 @@ files:
|
|
111
126
|
- spec/support/routes/rails3.rb
|
112
127
|
- spec/support/routes/rails4.rb
|
113
128
|
homepage: http://mrcalonso.com/rails-friendly-urls-gem/
|
114
|
-
licenses:
|
115
|
-
- MIT
|
129
|
+
licenses: []
|
116
130
|
metadata: {}
|
117
131
|
post_install_message:
|
118
132
|
rdoc_options: []
|
@@ -122,7 +136,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
122
136
|
requirements:
|
123
137
|
- - ">="
|
124
138
|
- !ruby/object:Gem::Version
|
125
|
-
version:
|
139
|
+
version: '0'
|
126
140
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
141
|
requirements:
|
128
142
|
- - ">="
|
@@ -130,11 +144,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
130
144
|
version: '0'
|
131
145
|
requirements: []
|
132
146
|
rubyforge_project:
|
133
|
-
rubygems_version: 2.
|
147
|
+
rubygems_version: 2.4.3
|
134
148
|
signing_key:
|
135
149
|
specification_version: 4
|
136
|
-
summary:
|
137
|
-
your project.
|
150
|
+
summary: Summary of RailsFriendlyUrls.
|
138
151
|
test_files:
|
139
152
|
- spec/apps/rails3_2.rb
|
140
153
|
- spec/apps/rails4.rb
|
@@ -147,4 +160,3 @@ test_files:
|
|
147
160
|
- spec/support/routes/rails3.rb
|
148
161
|
- spec/support/routes/rails4.rb
|
149
162
|
- spec/support/routes.rb
|
150
|
-
has_rdoc:
|
@@ -1,97 +0,0 @@
|
|
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
|
-
|