In Rails, is it possible to create a HTML 5 valueless attribute using any of the ActionView Helpers? I'm trying to create the HTML 5 itemprop microdata for google's BreadCrumbs. Here's the output I'd like to generate:
<div itemscope itemtype="http://data-vocabulary.org/Breadcrumb"></div>
But you can see that the itemscope attribute value has no value. Ideally, I'd like to开发者_运维百科 do something like this in Rails...
content_tag(:div, "somecontent", :itemscope => nil, :item_type => "http://data-vocabulary.org/Breadcrumb")
... but I can't seem to get generate an attribute without a value.
No, you can't. Rails' tag helper defines a ActionView::Helpers::TagHelper::BOOLEAN_ATTRIBUTES
array, and any attributes in that array will be outputted as key=key
, so if you had, say, tag(:input, :type => :checkbox, :checked => true)
, the output should be <input type='checkbox' checked='checked' />
.
I presume that this parses properly, since an XML parser is simply going to check for the presence of the attribute, so any value should work.
To that end, you could use:
content_tag(:div, "somecontent", :itemscope => "itemscope", :item_type ...
This will output itemscope="itemscope"
in the tag, but it should result in the same desired effect when parsed.
Alternately, you could add itemscope to the BOOLEAN_ATTRIBUTES, then specify :itemscope => true
.
You can achieve the result you want if you are willing to override a private Rails method. If you do this, you run the risk of causing problems when upgrading to future versions of Rails that update the private method logic. Since both <div itemscope ...>
and <div itemscope="itemscope" ...>
are valid according to the HTML5 spec, making the change below has very little payoff. The only reason I can think of to do this is if you are completely obsessive about your HTML code style.
As Chris Heald said, we will add itemscope
to BOOLEAN_ATTRIBUTES
and then override the tag helper to output boolean attributes without values. (The following tag_options method is modified from Rails/ActionPack 3.0.7 - future readers should copy the contemporary tag_options code and then make the change after the if BOOLEAN_ATTRIBUTES.include?(key)
line.)
module ActionView
module Helpers
module TagHelper
BOOLEAN_ATTRIBUTES.merge(['itemscope', :itemscope])
private
def tag_options(options, escape = true)
unless options.blank?
attrs = []
options.each_pair do |key, value|
if BOOLEAN_ATTRIBUTES.include?(key)
attrs << key.to_s if value
elsif !value.nil?
final_value = value.is_a?(Array) ? value.join(" ") : value
final_value = html_escape(final_value) if escape
attrs << %(#{key}="#{final_value}")
end
end
" #{attrs.sort * ' '}".html_safe unless attrs.empty?
end
end
end
end
end
You can now update your view with:
content_tag(:div, "somecontent", :itemscope => true, :item_type => "http://data-vocabulary.org/Breadcrumb"
FWIW, I store extensions to existing classes in e.g. lib/extensions/action_view.rb
; these extensions are loaded by config/initializers/extensions.rb
which consists of:
Dir[File.join(Rails.root, 'lib', 'extensions', '*.rb')].each {|f| require f}
精彩评论