prerender_rails 0.1.9 → 0.1.10

Sign up to get free protection for your applications and to get access to all the features.
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