gretel 2.1.0 → 2.2.0.rc1

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: 20b6074d04a88e299ce92a69065f183ba6e299ca
4
- data.tar.gz: 33fa2c8f9ff4cb909a430786d1e4b467ffec40f5
3
+ metadata.gz: 8655da4c27996c4a3cfa81b8e64b7096a9a8a59a
4
+ data.tar.gz: a108906eacb8b38d53fc748d55a57bab030d5dcd
5
5
  SHA512:
6
- metadata.gz: 38c61ee418788d568672b173f8fb72e67d45b00c6022210c37009a0bb9a53b6885c71d286647a583ebf0390544ee495e094129945919147161e201a2d68164a9
7
- data.tar.gz: af07be5e7434820b66b08f3e48959e8f123658ec5cd5f978264a80c2443480c70a46181f813ed38048d68fc2ff013490a3dfd03e067dca1e39f933be5084b104
6
+ metadata.gz: 2807debcf21aa80f5643bdef961003f299520469ad07e60e03ce9a0484b656e3b626edf56a957eec39126ef68dc43e7576a89b23d7f6192a1e199d910fad0f14
7
+ data.tar.gz: d69ab2b538e39e97de79ae712481f4bdd586062869ed552beb68af667f0ad4572c800baf01c550b9cc34af8c6416c8c96b9a3a892991ae1ba17a37c6fb0771c5
data/CHANGELOG.md CHANGED
@@ -1,6 +1,12 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
+ Version 2.2
5
+ -----------
6
+ * Support for setting trails via the URL – `params[:trail]`. This makes it possible to link to a different breadcrumb trail than the one specified in your breadcrumb,
7
+ for example if you have a store with products that have a default parent to their category, but when linking from the review section, you want to link back to the reviews instead.
8
+ See the readme for more info.
9
+
4
10
  Version 2.1
5
11
  -----------
6
12
  * Breadcrumbs are now configured in `config/breadcrumbs.rb` and `config/breadcrumbs/**/*.rb` and reloaded when changed in the development environment instead of the initializer that required restart when configuration changed.
data/README.md CHANGED
@@ -1,33 +1,19 @@
1
1
  [![Build Status](https://secure.travis-ci.org/lassebunk/gretel.png)](http://travis-ci.org/lassebunk/gretel)
2
2
 
3
3
  Gretel is a [Ruby on Rails](http://rubyonrails.org) plugin that makes it easy yet flexible to create breadcrumbs.
4
+ It is based around the idea that breadcrumbs are a separate concern, and therefore should be defined in their own place.
5
+ You define a set of breadcrumbs in the config folder and specify in the view which breadcrumb to use.
6
+ Gretel also supports [semantic breadcrumbs](http://support.google.com/webmasters/bin/answer.py?hl=en&answer=185417) (those used in Google results).
4
7
 
5
- New in version 2.1
6
- ------------------
7
- Instead of using the initializer that in Gretel version 2.0 and below required restarting the application after breadcrumb configuration changes, the configuration of the breadcrumbs is now loaded from `config/breadcrumbs.rb` (and `config/breadcrumbs/*.rb` if you want to split your breadcrumbs configuration across multiple files).
8
- In the Rails development environment, these files are automatically reloaded when changed.
9
-
10
- Using the initializer (e.g. `config/initializers/breadcrumbs.rb`) is deprecated but still supported until Gretel version 3.0.
11
-
12
- To update, use `bundle update gretel`. Then remove the `Gretel::Crumbs.layout do ... end` block, so instead of:
13
-
14
- ```ruby
15
- Gretel::Crumbs.layout do
16
- crumb :root do
17
- link "Home", root_path
18
- end
19
- end
20
- ```
8
+ Have fun! And please do write, if you (dis)like it – [lassebunk@gmail.com](mailto:lassebunk@gmail.com).
21
9
 
22
- in the initializer, you write:
10
+ New in version 2.2
11
+ ------------------
23
12
 
24
- ```ruby
25
- crumb :root do
26
- link "Home", root_path
27
- end
28
- ```
13
+ Gretel now supports setting trails via the URL – `params[:trail]`. This makes it possible to link to a different breadcrumb trail than the one specified in your breadcrumb,
14
+ for example if you have a store with products that have a default parent to their category, but when linking from the review section, you want to link back to the reviews instead.
29
15
 
30
- in `config/breadcrumbs.rb`.
16
+ See below for more info or the [changelog](https://github.com/lassebunk/gretel/blob/master/CHANGELOG.md) for more changes.
31
17
 
32
18
  Installation
33
19
  ------------
@@ -219,12 +205,58 @@ If you supply a block to the `breadcrumbs` method, it will yield an array with t
219
205
  <% end %>
220
206
  ```
221
207
 
208
+ Setting custom breadcrumb trails
209
+ --------------------------------
210
+
211
+ You can set a custom breadcrumb trail via `params[:trail]`. This makes it possible to link to a different breadcrumb trail than the one specified in your breadcrumb.
212
+
213
+ An example is if you have a store with products that have a default parent to their category, but when linking from the review section, you want to link back to the reviews instead.
214
+
215
+ ### Initial setup
216
+
217
+ To use breadcrumb trails, you must set a secret to be used when encoding the trails.
218
+
219
+ You can generate it using the installer:
220
+
221
+ ```bash
222
+ $ rails generate gretel:install
223
+ ```
224
+
225
+ This will create an initializer in *config/initializers/gretel.rb* that will contain a random secret key.
226
+
227
+ If you want to do it manually, you can put the following in *config/initializers/gretel.rb*:
228
+
229
+ ```
230
+ Gretel::Trail.secret = 'your_key_here' # Must be changed to something else to be secure
231
+ ```
232
+
233
+ You can generate a key using `SecureRandom.hex(64)`.
234
+
235
+ ### Example
236
+
237
+ This example shows how to link to the trail in the view.
238
+ Gretel has a built-in view helper method named `breadcrumb_trail` that contains the current breadcrumb trail ready for use in a URL.
239
+
240
+ ```erb
241
+ <% breadcrumb :reviews %>
242
+ ...
243
+ <% @products.each do |product| %>
244
+ <%= link_to @product.name, product_path(product, trail: breadcrumb_trail) %>
245
+ <% end %>
246
+ ```
247
+
248
+ The product view will now have the breadcrumb trail from the first page (reviews) instead of its default parent.
249
+
250
+ ### Note
251
+
252
+ Please use the trail functionality with care; the trails can get very long.
253
+
222
254
  Nice to know
223
255
  ------------
224
256
 
225
257
  ### Access to view helpers
226
258
 
227
- When inside `Gretel::Crumbs.layout do .. end`, you have access to all view helpers of the current view where the breadcrumbs are inserted.
259
+ When configuring breadcrumbs, you have access to all view helpers of the view where the breadcrumbs are inserted.
228
260
 
229
261
  ### Using multiple breadcrumb configuration files
230
262
 
@@ -235,6 +267,34 @@ The format is the same as `config/breadcrumbs.rb` which is also loaded.
235
267
 
236
268
  Since Gretel version 2.1.0, the breadcrumb configuration files are now reloaded in the Rails development environment if they change. In other environments, like production, the files are loaded once, when first needed.
237
269
 
270
+ Upgrading from version 2.0 or below
271
+ -----------------------------------
272
+ Instead of using the initializer that in Gretel version 2.0 and below required restarting the application after breadcrumb configuration changes, the configuration of the breadcrumbs is now loaded from `config/breadcrumbs.rb` (and `config/breadcrumbs/*.rb` if you want to split your breadcrumbs configuration across multiple files).
273
+ In the Rails development environment, these files are automatically reloaded when changed.
274
+
275
+ Using the initializer (e.g. `config/initializers/breadcrumbs.rb`) is deprecated but still supported until Gretel version 3.0.
276
+ If you want to silence the deprecation warning until you upgrade, you can set `Gretel.suppress_deprecation_warnings = true` before the layout block in your initializer.
277
+
278
+ To update to the latest version of Gretel, use `bundle update gretel`. Then remove the `Gretel::Crumbs.layout do ... end` block, so instead of:
279
+
280
+ ```ruby
281
+ Gretel::Crumbs.layout do
282
+ crumb :root do
283
+ link "Home", root_path
284
+ end
285
+ end
286
+ ```
287
+
288
+ in the initializer, you write:
289
+
290
+ ```ruby
291
+ crumb :root do
292
+ link "Home", root_path
293
+ end
294
+ ```
295
+
296
+ in `config/breadcrumbs.rb`.
297
+
238
298
  Documentation
239
299
  -------------
240
300
 
@@ -8,5 +8,12 @@ module Gretel
8
8
  def create_config_file
9
9
  copy_file "breadcrumbs.rb", "config/breadcrumbs.rb"
10
10
  end
11
+
12
+ desc "Creates an initializer with trail secret"
13
+ def create_initializer
14
+ initializer "gretel.rb" do
15
+ %{Gretel::Trail.secret = '#{SecureRandom.hex(64)}'}
16
+ end
17
+ end
11
18
  end
12
19
  end
data/lib/gretel.rb CHANGED
@@ -2,6 +2,7 @@ require 'gretel/version'
2
2
  require 'gretel/crumbs'
3
3
  require 'gretel/crumb'
4
4
  require 'gretel/link'
5
+ require 'gretel/trail'
5
6
  require 'gretel/view_helpers'
6
7
  require 'gretel/deprecated'
7
8
 
@@ -42,10 +43,11 @@ module Gretel
42
43
  # Sets the Rails environment names with automatic configuration reload. Default is +["development"]+.
43
44
  attr_writer :reload_environments
44
45
 
45
- # Resets all changes made to +Gretel+ and +Gretel::Crumbs+. Used for testing.
46
+ # Resets all changes made to +Gretel+, +Gretel::Crumbs+, and +Gretel::Trail+. Used for testing.
46
47
  def reset!
47
48
  instance_variables.each { |var| remove_instance_variable var }
48
49
  Crumbs.reset!
50
+ Trail.reset!
49
51
  end
50
52
  end
51
53
  end
data/lib/gretel/crumb.rb CHANGED
@@ -12,6 +12,9 @@ module Gretel
12
12
 
13
13
  # Sets link of the breadcrumb.
14
14
  def link(text, url = nil)
15
+ # Transform objects to real paths.
16
+ url = url_for(url) if url
17
+
15
18
  links << Gretel::Link.new(key, text, url)
16
19
  end
17
20
 
@@ -0,0 +1,73 @@
1
+ module Gretel
2
+ module Trail
3
+ class << self
4
+ # Secret used for crypting trail in URL that should be set to something
5
+ # unguessable. This is required when using trails, for the reason that
6
+ # unencrypted trails would be vulnerable to cross-site scripting attacks.
7
+ attr_accessor :secret
8
+
9
+ # Securely encodes array of links to a trail string to be used in URL.
10
+ def encode(links)
11
+ ensure_secret!
12
+
13
+ base64 = encode_base64(links)
14
+ hash = base64.crypt(secret)
15
+
16
+ [hash, base64].join("_")
17
+ end
18
+
19
+ # Securely decodes a URL trail string to array of links.
20
+ def decode(trail)
21
+ ensure_secret!
22
+
23
+ hash, base64 = trail.split("_", 2)
24
+
25
+ if base64.blank?
26
+ Rails.logger.info "[Gretel] Trail decode failed: No Base64 in trail"
27
+ []
28
+ elsif hash == base64.crypt(secret)
29
+ decode_base64(base64)
30
+ else
31
+ Rails.logger.info "[Gretel] Trail decode failed: Invalid hash '#{hash}' in trail"
32
+ []
33
+ end
34
+ end
35
+
36
+ # Name of trail param. Default: +:trail+.
37
+ def trail_param
38
+ @trail_param ||= :trail
39
+ end
40
+
41
+ attr_writer :trail_param
42
+
43
+ # Resets all changes made to +Gretel::Trail+. Used for testing.
44
+ def reset!
45
+ instance_variables.each { |var| remove_instance_variable var }
46
+ end
47
+
48
+ private
49
+
50
+ # Encodes links array to Base64, internally using YAML for serialization.
51
+ def encode_base64(links)
52
+ arr = links.map { |link| [link.key, link.text, link.url] }
53
+ Base64.urlsafe_encode64(arr.to_yaml)
54
+ end
55
+
56
+ # Decodes links array from Base64.
57
+ def decode_base64(base64)
58
+ yaml = Base64.urlsafe_decode64(base64)
59
+ arr = YAML.load(yaml)
60
+ arr.map { |key, text, url| Link.new(key, text, url) }
61
+ rescue
62
+ Rails.logger.info "[Gretel] Trail decode failed: Invalid Base64 '#{base64}' in trail"
63
+ []
64
+ end
65
+
66
+ # Ensures that a secret has been set, and raises an exception if this is not the case.
67
+ def ensure_secret!
68
+ raise "Gretel::Trail.secret is not set. Please set it to an unguessable string, e.g. from `rake secret`, or use `rails generate gretel:install` to generate and set it automatically." if secret.blank?
69
+ end
70
+
71
+ end
72
+ end
73
+ end
@@ -1,3 +1,3 @@
1
1
  module Gretel
2
- VERSION = "2.1.0"
2
+ VERSION = "2.2.0.rc1"
3
3
  end
@@ -10,6 +10,8 @@ module Gretel
10
10
  if args.any?
11
11
  @_breadcrumb_key = args.shift
12
12
  @_breadcrumb_args = args
13
+ @_breadcrumb_links = nil
14
+ @_breadcrumb_trail = nil
13
15
  else
14
16
  breadcrumbs(options)
15
17
  end
@@ -28,10 +30,8 @@ module Gretel
28
30
  # <% end %>
29
31
  # <% end %>
30
32
  def breadcrumbs(options = {})
31
- Gretel::Crumbs.reload_if_needed
32
-
33
33
  options = default_breadcrumb_options.merge(options)
34
- links = get_breadcrumb_links(options)
34
+ links = breadcrumb_links_for_render(options)
35
35
  if block_given?
36
36
  yield links
37
37
  else
@@ -39,20 +39,21 @@ module Gretel
39
39
  end
40
40
  end
41
41
 
42
- # Returns an array of links for the path of the breadcrumb set by +breadcrumb+.
43
- def get_breadcrumb_links(options = {})
44
- return [] if @_breadcrumb_key.blank?
42
+ def breadcrumb_trail
43
+ @_breadcrumb_trail ||= Gretel::Trail.encode(breadcrumb_links)
44
+ end
45
45
 
46
- # Get breadcrumb set by the `breadcrumb` method
47
- crumb = Gretel::Crumb.new(self, @_breadcrumb_key, *@_breadcrumb_args)
46
+ private
48
47
 
49
- # Links of first crumb
50
- links = crumb.links.dup
51
-
52
- # Build parents
53
- while crumb = crumb.parent
54
- links.unshift *crumb.links
48
+ def breadcrumb_links
49
+ @_breadcrumb_links ||= begin
50
+ Gretel::Crumbs.reload_if_needed
51
+ get_breadcrumb_links
55
52
  end
53
+ end
54
+
55
+ def breadcrumb_links_for_render(options = {})
56
+ links = breadcrumb_links.dup
56
57
 
57
58
  # Handle autoroot
58
59
  if options[:autoroot] && links.map(&:key).exclude?(:root) && Gretel::Crumbs.crumb_defined?(:root)
@@ -67,6 +68,33 @@ module Gretel
67
68
  links
68
69
  end
69
70
 
71
+ # Returns an array of links for the path of the breadcrumb set by +breadcrumb+.
72
+ def get_breadcrumb_links
73
+ return [] if @_breadcrumb_key.blank?
74
+
75
+ # Get breadcrumb set by the `breadcrumb` method
76
+ crumb = Gretel::Crumb.new(self, @_breadcrumb_key, *@_breadcrumb_args)
77
+
78
+ # Links of first crumb
79
+ links = crumb.links.dup
80
+
81
+ links.last.tap do |last|
82
+ last.url = request.try(:fullpath) || last.url
83
+ end
84
+
85
+ if params[Gretel::Trail.trail_param].present?
86
+ # Decode trail from URL
87
+ links.unshift *Gretel::Trail.decode(params[Gretel::Trail.trail_param])
88
+ else
89
+ # Build parents
90
+ while crumb = crumb.parent
91
+ links.unshift *crumb.links
92
+ end
93
+ end
94
+
95
+ links
96
+ end
97
+
70
98
  # Renders breadcrumbs HTML.
71
99
  def render_breadcrumbs(links, options)
72
100
  return "" if links.empty?
@@ -7,6 +7,7 @@ class HelperMethodsTest < ActionView::TestCase
7
7
 
8
8
  setup do
9
9
  Gretel.reset!
10
+ Gretel::Trail.secret = "128107d341e912db791d98bbe874a8250f784b0a0b4dbc5d5032c0fc1ca7bda9c6ece667bd18d23736ee833ea79384176faeb54d2e0d21012898dde78631cdf1"
10
11
  end
11
12
 
12
13
  test "shows basic breadcrumb" do
@@ -177,6 +178,29 @@ class HelperMethodsTest < ActionView::TestCase
177
178
  end
178
179
  end
179
180
 
181
+ test "trail helper" do
182
+ breadcrumb :basic
183
+
184
+ assert_equal "12hY7tdmRCBzQ_LS0tCi0gLSA6YmFzaWMKICAtIEFib3V0CiAgLSAvYWJvdXQK", breadcrumb_trail
185
+ end
186
+
187
+ test "loading trail" do
188
+ params[:trail] = "12hY7tdmRCBzQ_LS0tCi0gLSA6YmFzaWMKICAtIEFib3V0CiAgLSAvYWJvdXQK"
189
+ breadcrumb :multiple_links
190
+
191
+ assert_equal %{<div class="breadcrumbs"><a href="/">Home</a> &gt; <a href="/about">About</a> &gt; <a href="/about/contact">Contact</a> &gt; <span class="current">Contact form</span></div>},
192
+ breadcrumbs
193
+ end
194
+
195
+ test "different trail param" do
196
+ Gretel::Trail.trail_param = :mytest
197
+ params[:mytest] = "12hY7tdmRCBzQ_LS0tCi0gLSA6YmFzaWMKICAtIEFib3V0CiAgLSAvYWJvdXQK"
198
+ breadcrumb :multiple_links
199
+
200
+ assert_equal %{<div class="breadcrumbs"><a href="/">Home</a> &gt; <a href="/about">About</a> &gt; <a href="/about/contact">Contact</a> &gt; <span class="current">Contact form</span></div>},
201
+ breadcrumbs
202
+ end
203
+
180
204
  test "reload configuration when file is changed" do
181
205
  path = setup_loading_from_tmp_folder
182
206
  Gretel.reload_environments << "test"
@@ -0,0 +1,30 @@
1
+ require 'test_helper'
2
+
3
+ class TrailTest < ActiveSupport::TestCase
4
+ setup do
5
+ Gretel::Trail.secret = "128107d341e912db791d98bbe874a8250f784b0a0b4dbc5d5032c0fc1ca7bda9c6ece667bd18d23736ee833ea79384176faeb54d2e0d21012898dde78631cdf1"
6
+ @links = [
7
+ ["root", "Home", "/"],
8
+ ["store", "Store", "/store"],
9
+ ["search", "Search", "/store/search?q=test"]
10
+ ]
11
+ end
12
+
13
+ test "defaults" do
14
+ assert_equal :trail, Gretel::Trail.trail_param
15
+ end
16
+
17
+ test "encoding" do
18
+ assert_equal "12hY7tdmRCBzQ_LS0tCi0gLSByb290CiAgLSBIb21lCiAgLSAvCi0gLSBzdG9yZQogIC0gU3RvcmUKICAtIC9zdG9yZQotIC0gc2VhcmNoCiAgLSBTZWFyY2gKICAtIC9zdG9yZS9zZWFyY2g_cT10ZXN0Cg==",
19
+ Gretel::Trail.encode(@links.map { |key, text, url| Gretel::Link.new(key, text, url) })
20
+ end
21
+
22
+ test "decoding" do
23
+ assert_equal @links,
24
+ Gretel::Trail.decode("12hY7tdmRCBzQ_LS0tCi0gLSByb290CiAgLSBIb21lCiAgLSAvCi0gLSBzdG9yZQogIC0gU3RvcmUKICAtIC9zdG9yZQotIC0gc2VhcmNoCiAgLSBTZWFyY2gKICAtIC9zdG9yZS9zZWFyY2g_cT10ZXN0Cg==").map { |link| [link.key, link.text, link.url] }
25
+ end
26
+
27
+ test "invalid trail" do
28
+ assert_equal [], Gretel::Trail.decode("12hY7tdmRCBzZ_LS0tCi0gLSByb290CiAgLSBIb21lCiAgLSAvCi0gLSBzdG9yZQogIC0gU3RvcmUKICAtIC9zdG9yZQotIC0gc2VhcmNoCiAgLSBTZWFyY2gKICAtIC9zdG9yZS9zZWFyY2g_cT10ZXN0Cc==")
29
+ end
30
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gretel
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.2.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lasse Bunk
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-07-23 00:00:00.000000000 Z
11
+ date: 2013-10-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -62,6 +62,7 @@ files:
62
62
  - lib/gretel/crumbs.rb
63
63
  - lib/gretel/deprecated.rb
64
64
  - lib/gretel/link.rb
65
+ - lib/gretel/trail.rb
65
66
  - lib/gretel/version.rb
66
67
  - lib/gretel/view_helpers.rb
67
68
  - test/deprecated_test.rb
@@ -107,6 +108,7 @@ files:
107
108
  - test/gretel_test.rb
108
109
  - test/helper_methods_test.rb
109
110
  - test/test_helper.rb
111
+ - test/trail_test.rb
110
112
  homepage: http://github.com/lassebunk/gretel
111
113
  licenses:
112
114
  - MIT
@@ -122,9 +124,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
122
124
  version: '0'
123
125
  required_rubygems_version: !ruby/object:Gem::Requirement
124
126
  requirements:
125
- - - '>='
127
+ - - '>'
126
128
  - !ruby/object:Gem::Version
127
- version: '0'
129
+ version: 1.3.1
128
130
  requirements: []
129
131
  rubyforge_project:
130
132
  rubygems_version: 2.0.3
@@ -175,3 +177,4 @@ test_files:
175
177
  - test/gretel_test.rb
176
178
  - test/helper_methods_test.rb
177
179
  - test/test_helper.rb
180
+ - test/trail_test.rb