prerender_rails 0.1.9 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +59 -3
- data/lib/prerender_rails.rb +42 -2
- data/prerender_rails.gemspec +1 -1
- data/test/lib/prerender_rails.rb +25 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1773ce49f7fc96e82cc3a4186c4c9eb51f3c2479
|
4
|
+
data.tar.gz: 12ab0d5981038d66d85f5198e35f2592a46a2b74
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cdabf0df7454ac647756a966a2f7d3eecafa04f26fa2d293e278722442d1aaa5fcefcb07d0859a5789b178b730b54d4053ecfc9c55a3777e8b0eddd3527ee7d8
|
7
|
+
data.tar.gz: 52ffb587b5a76c393c44859477a693e675718d52f4ad180d9725f54b53ea28936cb2d9c5d6d0e75be28421c7041cc9ce4702e6a4fbf50c7e597657f3581ae4ea
|
data/README.md
CHANGED
@@ -5,9 +5,11 @@ Are you using backbone, angular, emberjs, etc, but you're unsure about the SEO i
|
|
5
5
|
|
6
6
|
Use this gem to install rails middleware that prerenders a javascript-rendered page using an external service and returns the HTML to the search engine crawler for SEO.
|
7
7
|
|
8
|
-
`Note:`
|
8
|
+
`Note:`
|
9
9
|
|
10
|
-
|
10
|
+
* If you are using a `#` in your urls, make sure to change it to `#!`. [View Google's ajax crawling protocol](https://developers.google.com/webmasters/ajax-crawling/docs/getting-started)
|
11
|
+
* Make sure you have more than one webserver thread/process running because the prerender service will make a request to your server to render the HTML.
|
12
|
+
* If you're testing on localhost, you need to run the prerender server locally so that it can access your server.
|
11
13
|
|
12
14
|
Add this line to your application's Gemfile:
|
13
15
|
|
@@ -28,6 +30,29 @@ And in `config/environment/production.rb`, add this line:
|
|
28
30
|
2. Make a `GET` request to the [prerender service](https://github.com/collectiveip/prerender)(phantomjs server) for the page's prerendered HTML
|
29
31
|
3. Return that HTML to the crawler
|
30
32
|
|
33
|
+
|
34
|
+
## Caching
|
35
|
+
|
36
|
+
This rails middleware is ready to be used with [redis](http://redis.io/) or [memcached](http://memcached.org/) to return prerendered pages in milliseconds.
|
37
|
+
|
38
|
+
When setting up the middleware in `config/environment/production.rb`, you can add a `before_render` method and `after_render` method for caching.
|
39
|
+
|
40
|
+
Here's an example testing a local redis cache:
|
41
|
+
|
42
|
+
_Put this in `config/environment/development.rb`, and add `gem 'redis'` to your Gemfile._
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
require 'redis'
|
46
|
+
@redis = Redis.new
|
47
|
+
config.middleware.use Rack::Prerender,
|
48
|
+
before_render: (Proc.new do |env|
|
49
|
+
@redis.get(Rack::Request.new(env).url)
|
50
|
+
end),
|
51
|
+
after_render: (Proc.new do |env, response|
|
52
|
+
@redis.set(Rack::Request.new(env).url, response.body)
|
53
|
+
end)
|
54
|
+
```
|
55
|
+
|
31
56
|
## Customization
|
32
57
|
|
33
58
|
### Whitelist
|
@@ -50,7 +75,38 @@ config.middleware.use Rack::Prerender, blacklist: '^/search'
|
|
50
75
|
config.middleware.use Rack::Prerender, blacklist: ['/search', '/users/.*/profile']
|
51
76
|
```
|
52
77
|
|
53
|
-
###
|
78
|
+
### before_render
|
79
|
+
|
80
|
+
This method is intended to be used for caching, but could be used to save analytics or anything else you need to do for each crawler request. If you return a string from before_render, the middleware will server that to the crawler instead of making a request to the prerender service.
|
81
|
+
```ruby
|
82
|
+
config.middleware.use Rack::Prerender,
|
83
|
+
before_render: (Proc.new do |env|
|
84
|
+
# do whatever you need to do.
|
85
|
+
end)
|
86
|
+
```
|
87
|
+
|
88
|
+
### after_render
|
89
|
+
|
90
|
+
This method is intended to be used for caching, but could be used to save analytics or anything else you need to do for each crawler request. This method is a noop and is called after the prerender service returns HTML.
|
91
|
+
```ruby
|
92
|
+
config.middleware.use Rack::Prerender,
|
93
|
+
after_render: (Proc.new do |env, response|
|
94
|
+
# do whatever you need to do.
|
95
|
+
end)
|
96
|
+
```
|
97
|
+
|
98
|
+
### build_rack_response_from_prerender
|
99
|
+
|
100
|
+
This method is intended to be used to modify the response before it is sent to the crawler. Use this method to add/remove response headers, or do anything else before the request is sent.
|
101
|
+
```ruby
|
102
|
+
config.middleware.use Rack::Prerender,
|
103
|
+
build_rack_response_from_prerender: (Proc.new do |response, prerender_response|
|
104
|
+
# response is already populated with the prerender status code, html, and headers
|
105
|
+
# prerender_response is the response that came back from the prerender service
|
106
|
+
end)
|
107
|
+
```
|
108
|
+
|
109
|
+
## Using your own prerender service
|
54
110
|
|
55
111
|
If you've deployed the prerender service on your own, set the `PRERENDER_SERVICE_URL` environment variable so that this package points there instead. Otherwise, it will default to the service already deployed at `http://prerender.herokuapp.com`
|
56
112
|
|
data/lib/prerender_rails.rb
CHANGED
@@ -62,13 +62,21 @@ module Rack
|
|
62
62
|
@app = app
|
63
63
|
end
|
64
64
|
|
65
|
-
def call(env)
|
66
65
|
|
66
|
+
def call(env)
|
67
67
|
if should_show_prerendered_page(env)
|
68
|
+
|
69
|
+
cached_response = before_render(env)
|
70
|
+
|
71
|
+
if cached_response && cached_response.is_a?(Rack::Response)
|
72
|
+
return cached_response.finish
|
73
|
+
end
|
74
|
+
|
68
75
|
prerendered_response = get_prerendered_page_response(env)
|
69
76
|
|
70
77
|
if prerendered_response
|
71
|
-
response =
|
78
|
+
response = build_rack_response_from_prerender(prerendered_response)
|
79
|
+
after_render(env, prerendered_response)
|
72
80
|
return response.finish
|
73
81
|
end
|
74
82
|
end
|
@@ -76,6 +84,7 @@ module Rack
|
|
76
84
|
@app.call(env)
|
77
85
|
end
|
78
86
|
|
87
|
+
|
79
88
|
def should_show_prerendered_page(env)
|
80
89
|
user_agent = env['HTTP_USER_AGENT']
|
81
90
|
return false if !user_agent
|
@@ -111,6 +120,7 @@ module Rack
|
|
111
120
|
return true
|
112
121
|
end
|
113
122
|
|
123
|
+
|
114
124
|
def get_prerendered_page_response(env)
|
115
125
|
begin
|
116
126
|
url = URI.parse(build_api_url(env))
|
@@ -123,6 +133,7 @@ module Rack
|
|
123
133
|
end
|
124
134
|
end
|
125
135
|
|
136
|
+
|
126
137
|
def build_api_url(env)
|
127
138
|
new_env = env
|
128
139
|
if env["CF-VISITOR"]
|
@@ -137,8 +148,37 @@ module Rack
|
|
137
148
|
"#{prerender_url}#{forward_slash}#{url}"
|
138
149
|
end
|
139
150
|
|
151
|
+
|
140
152
|
def get_prerender_service_url
|
141
153
|
@options[:prerender_service_url] || ENV['PRERENDER_SERVICE_URL'] || 'http://prerender.herokuapp.com/'
|
142
154
|
end
|
155
|
+
|
156
|
+
|
157
|
+
def build_rack_response_from_prerender(prerendered_response)
|
158
|
+
response = Rack::Response.new(prerendered_response.body, prerendered_response.code, prerendered_response.header)
|
159
|
+
|
160
|
+
@options[:build_rack_response_from_prerender].call(response, prerendered_response) if @options[:build_rack_response_from_prerender]
|
161
|
+
|
162
|
+
response
|
163
|
+
end
|
164
|
+
|
165
|
+
|
166
|
+
def before_render(env)
|
167
|
+
return nil unless @options[:before_render]
|
168
|
+
|
169
|
+
cached_render = @options[:before_render].call(env)
|
170
|
+
|
171
|
+
if cached_render && cached_render.is_a?(String)
|
172
|
+
Rack::Response.new(cached_render, 200, [])
|
173
|
+
else
|
174
|
+
nil
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
|
179
|
+
def after_render(env, response)
|
180
|
+
return true unless @options[:after_render]
|
181
|
+
@options[:after_render].call(env, response)
|
182
|
+
end
|
143
183
|
end
|
144
184
|
end
|
data/prerender_rails.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |spec|
|
4
4
|
spec.name = "prerender_rails"
|
5
|
-
spec.version = "0.1.
|
5
|
+
spec.version = "0.1.10"
|
6
6
|
spec.authors = ["Todd Hooper"]
|
7
7
|
spec.email = ["todd@collectiveip.com"]
|
8
8
|
spec.description = %q{Rails middleware to prerender your javascript heavy pages on the fly by a phantomjs service}
|
data/test/lib/prerender_rails.rb
CHANGED
@@ -13,6 +13,7 @@ describe Rack::Prerender do
|
|
13
13
|
@prerender = Rack::Prerender.new(@app)
|
14
14
|
end
|
15
15
|
|
16
|
+
|
16
17
|
it "should return a prerendered response for a crawler with the returned status code and headers" do
|
17
18
|
request = Rack::MockRequest.env_for "/", "HTTP_USER_AGENT" => bot
|
18
19
|
stub_request(:get, @prerender.build_api_url(request)).with(:headers => { 'User-Agent' => bot }).to_return(:body => "<html></html>", :status => 301, :headers => { 'Location' => 'http://google.com'})
|
@@ -23,6 +24,7 @@ describe Rack::Prerender do
|
|
23
24
|
assert_equal( { 'location' => 'http://google.com', 'Content-Length' => '13'}, response[2].headers )
|
24
25
|
end
|
25
26
|
|
27
|
+
|
26
28
|
it "should return a prerendered reponse if user is a bot by checking for _escaped_fragment_" do
|
27
29
|
request = Rack::MockRequest.env_for "/path?_escaped_fragment_=", "HTTP_USER_AGENT" => user
|
28
30
|
stub_request(:get, @prerender.build_api_url(request)).with(:headers => { 'User-Agent' => user }).to_return(:body => "<html></html>")
|
@@ -31,6 +33,7 @@ describe Rack::Prerender do
|
|
31
33
|
assert_equal ["<html></html>"], response[2].body
|
32
34
|
end
|
33
35
|
|
36
|
+
|
34
37
|
it "should continue to app routes if the url is a bad url with _escaped_fragment_" do
|
35
38
|
request = Rack::MockRequest.env_for "/path?query=string?_escaped_fragment_=", "HTTP_USER_AGENT" => user
|
36
39
|
response = Rack::Prerender.new(@app).call(request)
|
@@ -38,6 +41,7 @@ describe Rack::Prerender do
|
|
38
41
|
assert_equal "", response[2]
|
39
42
|
end
|
40
43
|
|
44
|
+
|
41
45
|
it "should continue to app routes if the request is not a GET" do
|
42
46
|
request = Rack::MockRequest.env_for "/path?_escaped_fragment_=", { "HTTP_USER_AGENT" => user, "REQUEST_METHOD" => "POST" }
|
43
47
|
response = Rack::Prerender.new(@app).call(request)
|
@@ -45,6 +49,7 @@ describe Rack::Prerender do
|
|
45
49
|
assert_equal "", response[2]
|
46
50
|
end
|
47
51
|
|
52
|
+
|
48
53
|
it "should continue to app routes if user is not a bot by checking agent string" do
|
49
54
|
request = Rack::MockRequest.env_for "/", "HTTP_USER_AGENT" => user
|
50
55
|
response = Rack::Prerender.new(@app).call(request)
|
@@ -52,6 +57,7 @@ describe Rack::Prerender do
|
|
52
57
|
assert_equal "", response[2]
|
53
58
|
end
|
54
59
|
|
60
|
+
|
55
61
|
it "should continue to app routes if user is a bot, but the bot is requesting a resource file" do
|
56
62
|
request = Rack::MockRequest.env_for "/main.js?anyQueryParam=true", "HTTP_USER_AGENT" => bot
|
57
63
|
response = Rack::Prerender.new(@app).call(request)
|
@@ -59,6 +65,7 @@ describe Rack::Prerender do
|
|
59
65
|
assert_equal "", response[2]
|
60
66
|
end
|
61
67
|
|
68
|
+
|
62
69
|
it "should continue to app routes if the url is not part of the regex specific whitelist" do
|
63
70
|
request = Rack::MockRequest.env_for "/saved/search/blah", "HTTP_USER_AGENT" => bot
|
64
71
|
response = Rack::Prerender.new(@app, whitelist: ['^/search', '/help']).call(request)
|
@@ -66,6 +73,7 @@ describe Rack::Prerender do
|
|
66
73
|
assert_equal "", response[2]
|
67
74
|
end
|
68
75
|
|
76
|
+
|
69
77
|
it "should return a prerendered response if the url is part of the regex specific whitelist" do
|
70
78
|
request = Rack::MockRequest.env_for "/search/things/123/page", "HTTP_USER_AGENT" => bot
|
71
79
|
stub_request(:get, @prerender.build_api_url(request)).to_return(:body => "<html></html>")
|
@@ -74,6 +82,7 @@ describe Rack::Prerender do
|
|
74
82
|
assert_equal ["<html></html>"], response[2].body
|
75
83
|
end
|
76
84
|
|
85
|
+
|
77
86
|
it "should continue to app routes if the url is part of the regex specific blacklist" do
|
78
87
|
request = Rack::MockRequest.env_for "/search/things/123/page", "HTTP_USER_AGENT" => bot
|
79
88
|
response = Rack::Prerender.new(@app, blacklist: ['^/search', '/help']).call(request)
|
@@ -81,6 +90,7 @@ describe Rack::Prerender do
|
|
81
90
|
assert_equal "", response[2]
|
82
91
|
end
|
83
92
|
|
93
|
+
|
84
94
|
it "should return a prerendered response if the url is not part of the regex specific blacklist" do
|
85
95
|
request = Rack::MockRequest.env_for "/profile/search/blah", "HTTP_USER_AGENT" => bot
|
86
96
|
stub_request(:get, @prerender.build_api_url(request)).to_return(:body => "<html></html>")
|
@@ -89,6 +99,7 @@ describe Rack::Prerender do
|
|
89
99
|
assert_equal ["<html></html>"], response[2].body
|
90
100
|
end
|
91
101
|
|
102
|
+
|
92
103
|
it "should continue to app routes if the referer is part of the regex specific blacklist" do
|
93
104
|
request = Rack::MockRequest.env_for "/api/results", "HTTP_USER_AGENT" => bot, "HTTP_REFERER" => '/search'
|
94
105
|
response = Rack::Prerender.new(@app, blacklist: ['^/search', '/help']).call(request)
|
@@ -96,6 +107,7 @@ describe Rack::Prerender do
|
|
96
107
|
assert_equal "", response[2]
|
97
108
|
end
|
98
109
|
|
110
|
+
|
99
111
|
it "should return a prerendered response if the referer is not part of the regex specific blacklist" do
|
100
112
|
request = Rack::MockRequest.env_for "/api/results", "HTTP_USER_AGENT" => bot, "HTTP_REFERER" => '/profile/search'
|
101
113
|
stub_request(:get, @prerender.build_api_url(request)).to_return(:body => "<html></html>")
|
@@ -103,6 +115,16 @@ describe Rack::Prerender do
|
|
103
115
|
|
104
116
|
assert_equal ["<html></html>"], response[2].body
|
105
117
|
end
|
118
|
+
|
119
|
+
|
120
|
+
it "should return a prerendered response returned from before_render" do
|
121
|
+
request = Rack::MockRequest.env_for "/", "HTTP_USER_AGENT" => bot
|
122
|
+
stub_request(:get, @prerender.build_api_url(request)).to_return(:body => "<html></html>")
|
123
|
+
response = Rack::Prerender.new(@app, before_render: Proc.new do |env| return '<html>cached</html>' end).call(request)
|
124
|
+
|
125
|
+
assert_equal ["<html>cached</html>"], response[2].body
|
126
|
+
end
|
127
|
+
|
106
128
|
|
107
129
|
describe '#buildApiUrl' do
|
108
130
|
it "should build the correct api url with the default url" do
|
@@ -111,6 +133,7 @@ describe Rack::Prerender do
|
|
111
133
|
assert_equal 'http://prerender.herokuapp.com/https://google.com/search?q=javascript', @prerender.build_api_url(request)
|
112
134
|
end
|
113
135
|
|
136
|
+
|
114
137
|
it "should build the correct api url with an environment variable url" do
|
115
138
|
ENV['PRERENDER_SERVICE_URL'] = 'http://prerenderurl.com'
|
116
139
|
request = Rack::MockRequest.env_for "https://google.com/search?q=javascript"
|
@@ -118,12 +141,14 @@ describe Rack::Prerender do
|
|
118
141
|
ENV['PRERENDER_SERVICE_URL'] = nil
|
119
142
|
end
|
120
143
|
|
144
|
+
|
121
145
|
it "should build the correct api url with an initialization variable url" do
|
122
146
|
@prerender = Rack::Prerender.new(@app, prerender_service_url: 'http://prerenderurl.com')
|
123
147
|
request = Rack::MockRequest.env_for "https://google.com/search?q=javascript"
|
124
148
|
assert_equal 'http://prerenderurl.com/https://google.com/search?q=javascript', @prerender.build_api_url(request)
|
125
149
|
end
|
126
150
|
|
151
|
+
|
127
152
|
# Check CF-Visitor header in order to Work behind CloudFlare with Flexible SSL (https://support.cloudflare.com/hc/en-us/articles/200170536)
|
128
153
|
it "should build the correct api url for the Cloudflare Flexible SSL support" do
|
129
154
|
request = Rack::MockRequest.env_for "http://google.com/search?q=javascript", { 'CF-VISITOR' => '"scheme":"https"'}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: prerender_rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Todd Hooper
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-11-
|
11
|
+
date: 2013-11-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|