zhulei-canonical-rails 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +40 -0
- data/Rakefile +31 -0
- data/app/helpers/canonical_rails/tag_helper.rb +77 -0
- data/config/routes.rb +3 -0
- data/lib/canonical-rails/engine.rb +9 -0
- data/lib/canonical-rails/version.rb +3 -0
- data/lib/canonical-rails.rb +39 -0
- data/lib/generators/canonical_rails/install/install_generator.rb +17 -0
- data/lib/generators/canonical_rails/install/templates/canonical_rails.rb +29 -0
- data/lib/tasks/canonical-rails_tasks.rake +4 -0
- metadata +131 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0b83aa32a3a10f89db41e84721bfbb81b4e638f1
|
4
|
+
data.tar.gz: a440ae9681fb7b8fbd542a68d25ae75c28a7188d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 067de9bc663b4ab9d7859b32efd7c4e2ec13138131c58b458659fb6539992910b61b4c309762d0de360089d7eefdfc624ab8ada20db387c04922c5d2933da042
|
7
|
+
data.tar.gz: b0b953000493e858924dff3b800433615e969a8ff5725b1355a311973e560dc3fe5e7a3d3ac1844bcaac353394b5bdf43438a9dd3c78562ea8973968016f7c89
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2012 YOURNAME
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
ZhuleiCanonicalRails
|
2
|
+
==============
|
3
|
+
[![Build Status](https://travis-ci.org/jumph4x/canonical-rails.svg?branch=master)](https://travis-ci.org/jumph4x/canonical-rails)
|
4
|
+
|
5
|
+
A number of articles exist explaining the issue concisely and at length:
|
6
|
+
|
7
|
+
* [Google Webmaster Blog Page About Specifying Canonical](http://googlewebmastercentral.blogspot.com/2009/02/specify-your-canonical.html)
|
8
|
+
* [Google Support About rel="canonical"](http://support.google.com/webmasters/bin/answer.py?hl=en&answer=139394)
|
9
|
+
* [Google Support About Canonicalization](http://support.google.com/webmasters/bin/answer.py?hl=en&answer=139066)
|
10
|
+
|
11
|
+
## Guide
|
12
|
+
|
13
|
+
Take a look at this blog post that can guide you through the idea and the setup: [Easily add canonical URLs to your Rails app](http://blog.planetargon.com/entries/2014/4/4/easily-add-canonical-urls-to-your-rails-app)
|
14
|
+
|
15
|
+
## Challenge
|
16
|
+
|
17
|
+
I've seen a lot of folks do more harm by neglecting canonicalization altogether than by applying too narrowly and conservatively, so here is an attempt to let people start modestly without spending too much time on it and whitelist parameters as they need to.
|
18
|
+
|
19
|
+
## Install
|
20
|
+
|
21
|
+
gem 'canonical-rails', github: 'jumph4x/canonical-rails'
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
First, generate the config
|
26
|
+
|
27
|
+
rails g canonical_rails:install
|
28
|
+
|
29
|
+
Then find it in config/initializers/ as canonical_rails.rb
|
30
|
+
|
31
|
+
Finally, include the canonical_tag helper inside the `head` portion of
|
32
|
+
your HTML views:
|
33
|
+
```ruby
|
34
|
+
<%= canonical_tag -%>
|
35
|
+
```
|
36
|
+
|
37
|
+
## Cred
|
38
|
+
|
39
|
+
A project by [Downshift Labs](http://downshiftlabs.com), Ruby on Rails,
|
40
|
+
Performance tuning and Spree Commerce projects.
|
data/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'ZhuleiCanonicalRails'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
|
24
|
+
load 'rails/tasks/engine.rake'
|
25
|
+
|
26
|
+
Bundler::GemHelper.install_tasks
|
27
|
+
|
28
|
+
require 'rspec/core/rake_task'
|
29
|
+
|
30
|
+
RSpec::Core::RakeTask.new(:spec)
|
31
|
+
task :default => :spec
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module ZhuleiCanonicalRails
|
2
|
+
module TagHelper
|
3
|
+
def trailing_slash_needed?
|
4
|
+
request.params.key?('action') && ZhuleiCanonicalRails.sym_collection_actions.include?(request.params['action'].to_sym)
|
5
|
+
end
|
6
|
+
|
7
|
+
def trailing_slash_if_needed
|
8
|
+
"/" if trailing_slash_needed? && request.path != '/'
|
9
|
+
end
|
10
|
+
|
11
|
+
def path_without_html_extension
|
12
|
+
request.path.sub(/\.html$/, '')
|
13
|
+
end
|
14
|
+
|
15
|
+
def canonical_protocol
|
16
|
+
ZhuleiCanonicalRails.protocol || request.protocol
|
17
|
+
end
|
18
|
+
|
19
|
+
def canonical_host
|
20
|
+
ZhuleiCanonicalRails.host || request.host
|
21
|
+
end
|
22
|
+
|
23
|
+
def canonical_port
|
24
|
+
(ZhuleiCanonicalRails.port || request.port).to_i
|
25
|
+
end
|
26
|
+
|
27
|
+
def canonical_href(host = canonical_host, port = canonical_port)
|
28
|
+
default_ports = { 'https://' => 443, 'http://' => 80 }
|
29
|
+
port = port.present? && port.to_i != default_ports[canonical_protocol] ? ":#{port}" : ''
|
30
|
+
raw "#{canonical_protocol}#{host}#{path_without_html_extension}#{whitelisted_query_string}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def canonical_path
|
34
|
+
raw "#{path_without_html_extension}#{trailing_slash_if_needed}#{whitelisted_query_string}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def canonical_tag(host = canonical_host, port = canonical_port)
|
38
|
+
canonical_url = canonical_href(host, port)
|
39
|
+
capture do
|
40
|
+
if ZhuleiCanonicalRails.opengraph_url
|
41
|
+
concat tag(:meta, property: 'og:url', content: canonical_url)
|
42
|
+
end
|
43
|
+
concat tag(:link, href: canonical_url, rel: :canonical)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def whitelisted_params
|
48
|
+
selected_params = params.select do |key, value|
|
49
|
+
value.present? && ZhuleiCanonicalRails.sym_whitelisted_parameters.include?(key.to_sym)
|
50
|
+
end
|
51
|
+
|
52
|
+
selected_params.respond_to?(:to_unsafe_h) ? selected_params.to_unsafe_h : selected_params.to_h
|
53
|
+
end
|
54
|
+
|
55
|
+
def whitelisted_query_string
|
56
|
+
# Rack 1.4.5 fails to handle params that are not strings
|
57
|
+
# So if
|
58
|
+
# my_hash = { "a" => 1, "b" => 2}
|
59
|
+
# Rack::Utils.build_nested_query(my_hash) would return
|
60
|
+
# "a&b"
|
61
|
+
# Rack 1.4.5 did not have a test case for this scenario
|
62
|
+
# https://github.com/rack/rack/blob/9939d40a5e23dcb058751d1029b794aa2f551900/test/spec_utils.rb#L222
|
63
|
+
# Rack 1.6.0 has it
|
64
|
+
# https://github.com/rack/rack/blob/65a7104b6b3e9ecd8f33c63a478ab9a33a103507/test/spec_utils.rb#L251
|
65
|
+
|
66
|
+
wl_params = whitelisted_params
|
67
|
+
|
68
|
+
"?" + Rack::Utils.build_nested_query(convert_numeric_params(wl_params)) if wl_params.present?
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def convert_numeric_params(params_hash)
|
74
|
+
Hash[params_hash.map { |k, v| v.is_a?(Numeric) ? [k, v.to_s] : [k, v] }]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
data/config/routes.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require "canonical-rails/engine"
|
2
|
+
|
3
|
+
module ZhuleiCanonicalRails
|
4
|
+
|
5
|
+
# Default way to setup ZhuleiCanonicalRails. Run `rails g canonical_rails:install` to create
|
6
|
+
# a fresh initializer with all configuration values.
|
7
|
+
#
|
8
|
+
# the config\setup concept politely observed at and borrowed from Devise: https://github.com/plataformatec/devise/blob/master/lib/devise.rb
|
9
|
+
|
10
|
+
def self.setup
|
11
|
+
yield self
|
12
|
+
end
|
13
|
+
|
14
|
+
mattr_accessor :host
|
15
|
+
@@host = nil
|
16
|
+
|
17
|
+
mattr_accessor :port
|
18
|
+
@@port = nil
|
19
|
+
|
20
|
+
mattr_accessor :protocol
|
21
|
+
@@protocol = nil
|
22
|
+
|
23
|
+
mattr_accessor :collection_actions
|
24
|
+
@@collection_actions = [:index]
|
25
|
+
|
26
|
+
mattr_accessor :whitelisted_parameters
|
27
|
+
@@whitelisted_parameters = []
|
28
|
+
|
29
|
+
mattr_accessor :opengraph_url
|
30
|
+
@@opengraph_url = false
|
31
|
+
|
32
|
+
def self.sym_collection_actions
|
33
|
+
@@sym_collection_actions ||= self.collection_actions.map(&:to_sym)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.sym_whitelisted_parameters
|
37
|
+
@@sym_whitelisted_parameters ||= self.whitelisted_parameters.map(&:to_sym)
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ZhuleiCanonicalRails
|
2
|
+
class InstallGenerator < Rails::Generators::Base
|
3
|
+
|
4
|
+
def self.source_paths
|
5
|
+
paths = []
|
6
|
+
paths << File.expand_path('../templates', "../../#{__FILE__}")
|
7
|
+
paths << File.expand_path('../templates', "../#{__FILE__}")
|
8
|
+
paths << File.expand_path('../templates', __FILE__)
|
9
|
+
paths.flatten
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_files
|
13
|
+
template 'canonical_rails.rb', 'config/initializers/canonical_rails.rb'
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# Do yourself a favor and set these up right when you install the engine.
|
2
|
+
|
3
|
+
ZhuleiCanonicalRails.setup do |config|
|
4
|
+
|
5
|
+
# Force the protocol. If you do not specify, the protocol will be based on the incoming request's protocol.
|
6
|
+
|
7
|
+
config.protocol#= 'https://'
|
8
|
+
|
9
|
+
# This is the main host, not just the TLD, omit slashes and protocol. If you have more than one, pick the one you want to rank in search results.
|
10
|
+
|
11
|
+
config.host# = 'www.mywebstore.com'
|
12
|
+
config.port# = '3000'
|
13
|
+
|
14
|
+
# http://en.wikipedia.org/wiki/URL_normalization
|
15
|
+
# Trailing slash represents semantics of a directory, ie a collection view - implying an :index get route;
|
16
|
+
# otherwise we have to assume semantics of an instance of a resource type, a member view - implying a :show get route
|
17
|
+
#
|
18
|
+
# Acts as a whitelist for routes to have trailing slashes
|
19
|
+
|
20
|
+
config.collection_actions# = [:index]
|
21
|
+
|
22
|
+
# Parameter spamming can cause index dilution by creating seemingly different URLs with identical or near-identical content.
|
23
|
+
# Unless whitelisted, these parameters will be omitted
|
24
|
+
|
25
|
+
config.whitelisted_parameters# = []
|
26
|
+
|
27
|
+
# Output a matching OpenGraph URL meta tag (og:url) with the canonical URL, as recommended by Facebook et al
|
28
|
+
config.opengraph_url#= true
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: zhulei-canonical-rails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Zhu Lei
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-09-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.1'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '5.3'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '4.1'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '5.3'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: appraisal
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
type: :development
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: sqlite3
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: rspec-rails
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '3.5'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '3.5'
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: pry
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
type: :development
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
description: This gem is based on canonical-rails by Denis Ivanov,I only delete the
|
90
|
+
port in the url and delete the lower-case method in the code.
|
91
|
+
email:
|
92
|
+
- zhuleichina@qq.com
|
93
|
+
executables: []
|
94
|
+
extensions: []
|
95
|
+
extra_rdoc_files: []
|
96
|
+
files:
|
97
|
+
- MIT-LICENSE
|
98
|
+
- README.md
|
99
|
+
- Rakefile
|
100
|
+
- app/helpers/canonical_rails/tag_helper.rb
|
101
|
+
- config/routes.rb
|
102
|
+
- lib/canonical-rails.rb
|
103
|
+
- lib/canonical-rails/engine.rb
|
104
|
+
- lib/canonical-rails/version.rb
|
105
|
+
- lib/generators/canonical_rails/install/install_generator.rb
|
106
|
+
- lib/generators/canonical_rails/install/templates/canonical_rails.rb
|
107
|
+
- lib/tasks/canonical-rails_tasks.rake
|
108
|
+
homepage: https://github.com/zhuleichina/canonical-rails
|
109
|
+
licenses: []
|
110
|
+
metadata: {}
|
111
|
+
post_install_message:
|
112
|
+
rdoc_options: []
|
113
|
+
require_paths:
|
114
|
+
- lib
|
115
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - ">="
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
requirements: []
|
126
|
+
rubyforge_project:
|
127
|
+
rubygems_version: 2.6.14
|
128
|
+
signing_key:
|
129
|
+
specification_version: 4
|
130
|
+
summary: Simple and configurable Rails canonical ref tag helper
|
131
|
+
test_files: []
|