diff options
Diffstat (limited to 'actionview')
-rw-r--r-- | actionview/CHANGELOG.md | 10 | ||||
-rw-r--r-- | actionview/lib/action_view/helpers/tags.rb | 1 | ||||
-rw-r--r-- | actionview/lib/action_view/helpers/tags/label.rb | 16 | ||||
-rw-r--r-- | actionview/lib/action_view/helpers/tags/placeholderable.rb | 18 | ||||
-rw-r--r-- | actionview/lib/action_view/helpers/tags/translator.rb | 40 | ||||
-rw-r--r-- | actionview/lib/action_view/helpers/url_helper.rb | 4 | ||||
-rw-r--r-- | actionview/lib/action_view/renderer/partial_renderer.rb | 5 | ||||
-rw-r--r-- | actionview/test/actionpack/controller/render_test.rb | 4 | ||||
-rw-r--r-- | actionview/test/fixtures/test/_FooBar.html.erb | 1 | ||||
-rw-r--r-- | actionview/test/fixtures/test/_a-in.html.erb | 0 | ||||
-rw-r--r-- | actionview/test/lib/controller/fake_models.rb | 16 | ||||
-rw-r--r-- | actionview/test/template/form_helper_test.rb | 54 | ||||
-rw-r--r-- | actionview/test/template/render_test.rb | 21 |
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 |