aboutsummaryrefslogtreecommitdiffstats
path: root/actionview
diff options
context:
space:
mode:
Diffstat (limited to 'actionview')
-rw-r--r--actionview/CHANGELOG.md10
-rw-r--r--actionview/lib/action_view/helpers/tags.rb1
-rw-r--r--actionview/lib/action_view/helpers/tags/label.rb16
-rw-r--r--actionview/lib/action_view/helpers/tags/placeholderable.rb18
-rw-r--r--actionview/lib/action_view/helpers/tags/translator.rb40
-rw-r--r--actionview/lib/action_view/helpers/url_helper.rb4
-rw-r--r--actionview/lib/action_view/renderer/partial_renderer.rb5
-rw-r--r--actionview/test/actionpack/controller/render_test.rb4
-rw-r--r--actionview/test/fixtures/test/_FooBar.html.erb1
-rw-r--r--actionview/test/fixtures/test/_a-in.html.erb0
-rw-r--r--actionview/test/lib/controller/fake_models.rb16
-rw-r--r--actionview/test/template/form_helper_test.rb54
-rw-r--r--actionview/test/template/render_test.rb21
13 files changed, 142 insertions, 48 deletions
diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md
index 743c01e393..7fc32a3b5c 100644
--- a/actionview/CHANGELOG.md
+++ b/actionview/CHANGELOG.md
@@ -1,3 +1,13 @@
+* Partial template name does no more have to be a valid Ruby identifier.
+
+ There used to be a naming rule that the partial name should start with
+ underscore, and should be followed by any combination of letters, numbers
+ and underscores.
+ But now we can give our partials any name starting with underscore, such as
+ _🍔.html.erb.
+
+ *Akira Matsuda*
+
* Change the default template handler from `ERB` to `Raw`.
Files without a template handler in their extension will be rendered using the raw
diff --git a/actionview/lib/action_view/helpers/tags.rb b/actionview/lib/action_view/helpers/tags.rb
index 45c75d10c0..a4f6eb0150 100644
--- a/actionview/lib/action_view/helpers/tags.rb
+++ b/actionview/lib/action_view/helpers/tags.rb
@@ -5,6 +5,7 @@ module ActionView
eager_autoload do
autoload :Base
+ autoload :Translator
autoload :CheckBox
autoload :CollectionCheckBoxes
autoload :CollectionRadioButtons
diff --git a/actionview/lib/action_view/helpers/tags/label.rb b/actionview/lib/action_view/helpers/tags/label.rb
index 08a23e497e..b31d5fda66 100644
--- a/actionview/lib/action_view/helpers/tags/label.rb
+++ b/actionview/lib/action_view/helpers/tags/label.rb
@@ -15,20 +15,10 @@ module ActionView
def translation
method_and_value = @tag_value.present? ? "#{@method_name}.#{@tag_value}" : @method_name
- @object_name.gsub!(/\[(.*)_attributes\]\[\d+\]/, '.\1')
-
- if object.respond_to?(:to_model)
- key = object.model_name.i18n_key
- i18n_default = ["#{key}.#{method_and_value}".to_sym, ""]
- end
-
- i18n_default ||= ""
- content = I18n.t("#{@object_name}.#{method_and_value}", :default => i18n_default, :scope => "helpers.label").presence
-
- content ||= if object && object.class.respond_to?(:human_attribute_name)
- object.class.human_attribute_name(method_and_value)
- end
+ content ||= Translator
+ .new(object, @object_name, method_and_value, scope: "helpers.label")
+ .translate
content ||= @method_name.humanize
content
diff --git a/actionview/lib/action_view/helpers/tags/placeholderable.rb b/actionview/lib/action_view/helpers/tags/placeholderable.rb
index ae67bc13af..cf7b117614 100644
--- a/actionview/lib/action_view/helpers/tags/placeholderable.rb
+++ b/actionview/lib/action_view/helpers/tags/placeholderable.rb
@@ -7,24 +7,12 @@ module ActionView
if tag_value = @options[:placeholder]
placeholder = tag_value if tag_value.is_a?(String)
-
- object_name = @object_name.gsub(/\[(.*)_attributes\]\[\d+\]/, '.\1')
method_and_value = tag_value.is_a?(TrueClass) ? @method_name : "#{@method_name}.#{tag_value}"
- if object.respond_to?(:to_model)
- key = object.class.model_name.i18n_key
- i18n_default = ["#{key}.#{method_and_value}".to_sym, ""]
- end
-
- i18n_default ||= ""
- placeholder ||= I18n.t("#{object_name}.#{method_and_value}", :default => i18n_default, :scope => "helpers.placeholder").presence
-
- placeholder ||= if object && object.class.respond_to?(:human_attribute_name)
- object.class.human_attribute_name(method_and_value)
- end
-
+ placeholder ||= Tags::Translator
+ .new(object, @object_name, method_and_value, scope: "helpers.placeholder")
+ .translate
placeholder ||= @method_name.humanize
-
@options[:placeholder] = placeholder
end
end
diff --git a/actionview/lib/action_view/helpers/tags/translator.rb b/actionview/lib/action_view/helpers/tags/translator.rb
new file mode 100644
index 0000000000..8b6655481d
--- /dev/null
+++ b/actionview/lib/action_view/helpers/tags/translator.rb
@@ -0,0 +1,40 @@
+module ActionView
+ module Helpers
+ module Tags # :nodoc:
+ class Translator # :nodoc:
+ def initialize(object, object_name, method_and_value, scope:)
+ @object_name = object_name.gsub(/\[(.*)_attributes\]\[\d+\]/, '.\1')
+ @method_and_value = method_and_value
+ @scope = scope
+ @model = object.respond_to?(:to_model) ? object.to_model : nil
+ end
+
+ def translate
+ translated_attribute = I18n.t("#{object_name}.#{method_and_value}", default: i18n_default, scope: scope).presence
+ translated_attribute || human_attribute_name
+ end
+
+ protected
+
+ attr_reader :object_name, :method_and_value, :scope, :model
+
+ private
+
+ def i18n_default
+ if model
+ key = model.model_name.i18n_key
+ ["#{key}.#{method_and_value}".to_sym, ""]
+ else
+ ""
+ end
+ end
+
+ def human_attribute_name
+ if model && model.class.respond_to?(:human_attribute_name)
+ model.class.human_attribute_name(method_and_value)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/actionview/lib/action_view/helpers/url_helper.rb b/actionview/lib/action_view/helpers/url_helper.rb
index 8c2d5705f1..33882063f9 100644
--- a/actionview/lib/action_view/helpers/url_helper.rb
+++ b/actionview/lib/action_view/helpers/url_helper.rb
@@ -46,9 +46,9 @@ module ActionView
end
protected :_back_url
- # Creates a link tag of the given +name+ using a URL created by the set of +options+.
+ # Creates an anchor element of the given +name+ using a URL created by the set of +options+.
# See the valid options in the documentation for +url_for+. It's also possible to
- # pass a String instead of an options hash, which generates a link tag that uses the
+ # pass a String instead of an options hash, which generates an anchor element that uses the
# value of the String as the href for the link. Using a <tt>:back</tt> Symbol instead
# of an options hash will generate a link to the referrer (a JavaScript back link
# will be used in place of a referrer if none exists). If +nil+ is passed as the name
diff --git a/actionview/lib/action_view/renderer/partial_renderer.rb b/actionview/lib/action_view/renderer/partial_renderer.rb
index 6c3015180a..5ff15411cf 100644
--- a/actionview/lib/action_view/renderer/partial_renderer.rb
+++ b/actionview/lib/action_view/renderer/partial_renderer.rb
@@ -519,7 +519,7 @@ module ActionView
def retrieve_variable(path, as)
variable = as || begin
base = path[-1] == "/" ? "" : File.basename(path)
- raise_invalid_identifier(path) unless base =~ /\A_?([a-z]\w*)(\.\w+)*\z/
+ raise_invalid_identifier(path) unless base =~ /\A_?(.*)(?:\.\w+)*\z/
$1.to_sym
end
if @collection
@@ -530,8 +530,7 @@ module ActionView
end
IDENTIFIER_ERROR_MESSAGE = "The partial name (%s) is not a valid Ruby identifier; " +
- "make sure your partial name starts with underscore, " +
- "and is followed by any combination of letters, numbers and underscores."
+ "make sure your partial name starts with underscore."
OPTION_AS_ERROR_MESSAGE = "The value (%s) of the option `as` is not a valid Ruby identifier; " +
"make sure it starts with lowercase letter, " +
diff --git a/actionview/test/actionpack/controller/render_test.rb b/actionview/test/actionpack/controller/render_test.rb
index 0a8842b527..fe4cf3688a 100644
--- a/actionview/test/actionpack/controller/render_test.rb
+++ b/actionview/test/actionpack/controller/render_test.rb
@@ -968,12 +968,12 @@ class RenderTest < ActionController::TestCase
end
def test_should_implicitly_render_html_template_from_xhr_request
- xhr :get, :render_implicit_html_template_from_xhr_request
+ get :render_implicit_html_template_from_xhr_request, xhr: true
assert_equal "XHR!\nHello HTML!", @response.body
end
def test_should_implicitly_render_js_template_without_layout
- xhr :get, :render_implicit_js_template_without_layout, :format => :js
+ get :render_implicit_js_template_without_layout, format: :js, xhr: true
assert_no_match %r{<html>}, @response.body
end
diff --git a/actionview/test/fixtures/test/_FooBar.html.erb b/actionview/test/fixtures/test/_FooBar.html.erb
new file mode 100644
index 0000000000..4bbe59410a
--- /dev/null
+++ b/actionview/test/fixtures/test/_FooBar.html.erb
@@ -0,0 +1 @@
+🍣
diff --git a/actionview/test/fixtures/test/_a-in.html.erb b/actionview/test/fixtures/test/_a-in.html.erb
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/actionview/test/fixtures/test/_a-in.html.erb
diff --git a/actionview/test/lib/controller/fake_models.rb b/actionview/test/lib/controller/fake_models.rb
index 789b1d198b..65c68fc34a 100644
--- a/actionview/test/lib/controller/fake_models.rb
+++ b/actionview/test/lib/controller/fake_models.rb
@@ -54,6 +54,22 @@ class Post < Struct.new(:title, :author_name, :body, :secret, :persisted, :writt
def tags_attributes=(attributes); end
end
+class PostDelegator < Post
+ def to_model
+ PostDelegate.new
+ end
+end
+
+class PostDelegate < Post
+ def self.human_attribute_name(attribute)
+ "Delegate #{super}"
+ end
+
+ def model_name
+ ActiveModel::Name.new(self.class)
+ end
+end
+
class Comment
extend ActiveModel::Naming
include ActiveModel::Conversion
diff --git a/actionview/test/template/form_helper_test.rb b/actionview/test/template/form_helper_test.rb
index dccf6a2090..4e336bea63 100644
--- a/actionview/test/template/form_helper_test.rb
+++ b/actionview/test/template/form_helper_test.rb
@@ -40,6 +40,9 @@ class FormHelperTest < ActionView::TestCase
},
tag: {
value: "Tag"
+ },
+ post_delegate: {
+ title: 'Delegate model_name title'
}
}
}
@@ -81,6 +84,9 @@ class FormHelperTest < ActionView::TestCase
body: "Write body here"
}
},
+ post_delegate: {
+ title: 'Delegate model_name title'
+ },
tag: {
value: "Tag"
}
@@ -117,6 +123,10 @@ class FormHelperTest < ActionView::TestCase
@post.tags = []
@post.tags << Tag.new
+ @post_delegator = PostDelegator.new
+
+ @post_delegator.title = 'Hello World'
+
@car = Car.new("#000FFF")
end
@@ -249,6 +259,18 @@ class FormHelperTest < ActionView::TestCase
end
end
+ def test_label_with_non_active_record_object
+ form_for(OpenStruct.new(name:'ok'), as: 'person', url: 'an_url', html: { id: 'create-person' }) do |f|
+ f.label(:name)
+ end
+
+ expected = whole_form("an_url", "create-person", "new_person", method: "post") do
+ '<label for="person_name">Name</label>'
+ end
+
+ assert_dom_equal expected, output_buffer
+ end
+
def test_label_with_for_attribute_as_symbol
assert_dom_equal('<label for="my_for">Title</label>', label(:post, :title, nil, for: "my_for"))
end
@@ -337,6 +359,22 @@ class FormHelperTest < ActionView::TestCase
)
end
+ def test_label_with_to_model
+ assert_dom_equal(
+ %{<label for="post_delegator_title">Delegate Title</label>},
+ label(:post_delegator, :title)
+ )
+ end
+
+ def test_label_with_to_model_and_overriden_model_name
+ with_locale :label do
+ assert_dom_equal(
+ %{<label for="post_delegator_title">Delegate model_name title</label>},
+ label(:post_delegator, :title)
+ )
+ end
+ end
+
def test_text_field_placeholder_without_locales
with_locale :placeholder do
assert_dom_equal('<input id="post_body" name="post[body]" placeholder="Body" type="text" value="Back to the hill and over it again!" />', text_field(:post, :body, placeholder: true))
@@ -349,12 +387,28 @@ class FormHelperTest < ActionView::TestCase
end
end
+ def test_text_field_placeholder_with_locales_and_to_model
+ with_locale :placeholder do
+ assert_dom_equal(
+ '<input id="post_delegator_title" name="post_delegator[title]" placeholder="Delegate model_name title" type="text" value="Hello World" />',
+ text_field(:post_delegator, :title, placeholder: true)
+ )
+ end
+ end
+
def test_text_field_placeholder_with_human_attribute_name
with_locale :placeholder do
assert_dom_equal('<input id="post_cost" name="post[cost]" placeholder="Total cost" type="text" />', text_field(:post, :cost, placeholder: true))
end
end
+ def test_text_field_placeholder_with_human_attribute_name_and_to_model
+ assert_dom_equal(
+ '<input id="post_delegator_title" name="post_delegator[title]" placeholder="Delegate Title" type="text" value="Hello World" />',
+ text_field(:post_delegator, :title, placeholder: true)
+ )
+ end
+
def test_text_field_placeholder_with_string_value
with_locale :placeholder do
assert_dom_equal('<input id="post_cost" name="post[cost]" placeholder="HOW MUCH?" type="text" />', text_field(:post, :cost, placeholder: "HOW MUCH?"))
diff --git a/actionview/test/template/render_test.rb b/actionview/test/template/render_test.rb
index 66667e0474..f77b81f0ee 100644
--- a/actionview/test/template/render_test.rb
+++ b/actionview/test/template/render_test.rb
@@ -171,18 +171,12 @@ module RenderTestCases
assert_equal "only partial", @view.render("test/partial_only", :counter_counter => 5)
end
- def test_render_partial_with_invalid_name
- e = assert_raises(ArgumentError) { @view.render(:partial => "test/200") }
- assert_equal "The partial name (test/200) is not a valid Ruby identifier; " +
- "make sure your partial name starts with underscore, " +
- "and is followed by any combination of letters, numbers and underscores.", e.message
+ def test_render_partial_with_number
+ assert_nothing_raised { @view.render(:partial => "test/200") }
end
def test_render_partial_with_missing_filename
- e = assert_raises(ArgumentError) { @view.render(:partial => "test/") }
- assert_equal "The partial name (test/) is not a valid Ruby identifier; " +
- "make sure your partial name starts with underscore, " +
- "and is followed by any combination of letters, numbers and underscores.", e.message
+ assert_raises(ActionView::MissingTemplate) { @view.render(:partial => "test/") }
end
def test_render_partial_with_incompatible_object
@@ -190,11 +184,12 @@ module RenderTestCases
assert_equal "'#{nil.inspect}' is not an ActiveModel-compatible object. It must implement :to_partial_path.", e.message
end
+ def test_render_partial_starting_with_a_capital
+ assert_nothing_raised { @view.render(:partial => 'test/FooBar') }
+ end
+
def test_render_partial_with_hyphen
- e = assert_raises(ArgumentError) { @view.render(:partial => "test/a-in") }
- assert_equal "The partial name (test/a-in) is not a valid Ruby identifier; " +
- "make sure your partial name starts with underscore, " +
- "and is followed by any combination of letters, numbers and underscores.", e.message
+ assert_nothing_raised { @view.render(:partial => "test/a-in") }
end
def test_render_partial_with_invalid_option_as