Skip to content

Commit e4aaac1

Browse files
committed
Fix sorting of helpers from different paths
When more than one directory for helpers is provided to a controller, it should preserver the order of directories. Given 2 paths: MyController.helpers_paths = ["dir1/helpers", "dir2/helpers"] helpers from dir1 should be loaded first. Before this commit, all helpers were mixed and then sorted alphabetically, which essentially would require to rename helpers to get desired order. This is a problem especially for engines, where you would like to be able to predict accurately which engine helpers will load first. (closes rails#6496)
1 parent 523d0f0 commit e4aaac1

File tree

6 files changed

+57
-2
lines changed

6 files changed

+57
-2
lines changed

actionpack/CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
## Rails 4.0.0 (unreleased) ##
22

3+
* change a way of ordering helpers from several directories. Previously,
4+
when loading helpers from multiple paths, all of the helpers files were
5+
gathered into one array an then they were sorted. Helpers from different
6+
directories should not be mixed before loading them to make loading more
7+
predictable. The most common use case for such behavior is loading helpers
8+
from engines. When you load helpers from application and engine Foo, in
9+
that order, first rails will load all of the helpers from application,
10+
sorted alphabetically and then it will do the same for Foo engine.
11+
12+
*Piotr Sarnacki*
13+
314
* `truncate` now always returns an escaped HTMl-safe string. The option `:escape` can be used as
415
false to not escape the result.
516

actionpack/lib/action_controller/metal/helpers.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,9 @@ def all_helpers_from_path(path)
9595
helpers = []
9696
Array(path).each do |_path|
9797
extract = /^#{Regexp.quote(_path.to_s)}\/?(.*)_helper.rb$/
98-
helpers += Dir["#{_path}/**/*_helper.rb"].map { |file| file.sub(extract, '\1') }
98+
names = Dir["#{_path}/**/*_helper.rb"].map { |file| file.sub(extract, '\1') }
99+
helpers += names.sort
99100
end
100-
helpers.sort!
101101
helpers.uniq!
102102
helpers
103103
end

actionpack/test/controller/helper_test.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,42 @@ def lib
4646
class MeTooController < JustMeController
4747
end
4848

49+
class HelpersPathsController < ActionController::Base
50+
paths = ["helpers2_pack", "helpers1_pack"].map do |path|
51+
File.join(File.expand_path('../../fixtures', __FILE__), path)
52+
end
53+
$:.unshift(*paths)
54+
55+
self.helpers_path = paths
56+
helper :all
57+
58+
def index
59+
render :inline => "<%= conflicting_helper %>"
60+
end
61+
end
62+
4963
module LocalAbcHelper
5064
def a() end
5165
def b() end
5266
def c() end
5367
end
5468

69+
class HelperPathsTest < ActiveSupport::TestCase
70+
def setup
71+
@request = ActionController::TestRequest.new
72+
@response = ActionController::TestResponse.new
73+
end
74+
75+
def test_helpers_paths_priority
76+
request = ActionController::TestRequest.new
77+
responses = HelpersPathsController.action(:index).call(request.env)
78+
79+
# helpers1_pack was given as a second path, so pack1_helper should be
80+
# included as the second one
81+
assert_equal "pack1", responses.last.body
82+
end
83+
end
84+
5585
class HelperTest < ActiveSupport::TestCase
5686
class TestController < ActionController::Base
5787
attr_accessor :delegate_attr
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module Pack1Helper
2+
def conflicting_helper
3+
"pack1"
4+
end
5+
end
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module Pack2Helper
2+
def conflicting_helper
3+
"pack2"
4+
end
5+
end

guides/source/upgrading_ruby_on_rails.textile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ h4(#action_pack4_0). ActionPack
4646

4747
Rails 4.0 changed how <tt>assert_generates</tt>, <tt>assert_recognizes</tt>, and <tt>assert_routing</tt> work. Now all these assertions raise <tt>Assertion</tt> instead of <tt>RoutingError</tt>.
4848

49+
h4(#helpers_order). Helpers loading order
50+
51+
The loading order of helpers from more than one directory has changed in Rails 4.0. Previously, helpers from all directories were gathered and then sorted alphabetically. After upgrade to Rails 4.0 helpers will preserve the order of loaded directories and will be sorted alphabetically only within each directory. Unless you explicitly use <tt>helpers_path</tt> parameter, this change will only impact the way of loading helpers from engines. If you rely on the fact that particular helper from engine loads before or after another helper from application or another engine, you should check if correct methods are available after upgrade. If you would like to change order in which engines are loaded, you can use <tt>config.railties_order=</tt> method.
52+
4953
h3. Upgrading from Rails 3.1 to Rails 3.2
5054

5155
If your application is currently on any version of Rails older than 3.1.x, you should upgrade to Rails 3.1 before attempting an update to Rails 3.2.

0 commit comments

Comments
 (0)