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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dd646cf6503266ed2db50c786e116d740e63c4c9
4
- data.tar.gz: 07cea4440350844c52ae3a29a483a00baefc1dba
3
+ metadata.gz: 1773ce49f7fc96e82cc3a4186c4c9eb51f3c2479
4
+ data.tar.gz: 12ab0d5981038d66d85f5198e35f2592a46a2b74
5
5
  SHA512:
6
- metadata.gz: a37f41bb0b7535a9b0386191a231697be90e468614875dd4cf8a3b75781407ca8784b33051f08e539eb0a18f5d345f0bde8c611896abcd5faf08e6862efe3909
7
- data.tar.gz: 447741f462ae27b1a4f11fc8a4f6c72ffbc92153e69a682c0eb3b24e74f6ba007166bc574fdc1388c49f61efa1dea7b4d407c1316ba0976bcc4e1e1eab52012c
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:` 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)
8
+ `Note:`
9
9
 
10
- `Note:` 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.
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
- ### Using your own prerender service
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
 
@@ -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 = Rack::Response.new(prerendered_response.body, prerendered_response.code, prerendered_response.header)
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
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = "prerender_rails"
5
- spec.version = "0.1.9"
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}
@@ -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.9
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-16 00:00:00.000000000 Z
11
+ date: 2013-11-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack