Using is_a? to vet method params
In Today’s Rails we’re inside the button_to helper once again.
You may remember that this helper will make a whole RESTful form for you containing just one button.
is_a?
This helper can be called in several different ways, with strings, hashes and an optional block. In this section we’ll look how Rails allows us to call a method in so many differnt ways, and specifically at Object#is_a?.
Here’s a reminder of the helper code:
def button_to(name = nil, options = nil, html_options = nil, &block)
html_options, options = options, name if block_given?
options ||= {}
html_options ||= {}
html_options = html_options.stringify_keys
convert_boolean_attributes!(html_options, %w(disabled))
url = options.is_a?(String) ? options : url_for(options)
remote = html_options.delete('remote')
method = html_options.delete('method').to_s
method_tag = BUTTON_TAG_METHOD_VERBS.include?(method) ? method_tag(method) : ''.html_safe
form_method = method == 'get' ? 'get' : 'post'
form_options = html_options.delete('form') || {}
form_options[:class] ||= html_options.delete('form_class') || 'button_to'
form_options.merge!(method: form_method, action: url)
form_options.merge!("data-remote" => "true") if remote
request_token_tag = form_method == 'post' ? token_tag : ''
html_options = convert_options_to_data_attributes(options, html_options)
html_options['type'] = 'submit'
button = if block_given?
content_tag('button', html_options, &block)
else
html_options['value'] = name || url
tag('input', html_options)
end
inner_tags = method_tag.safe_concat(button).safe_concat(request_token_tag)
content_tag('form', content_tag('div', inner_tags), form_options)
end
is_a?
%p On line 9 we see a use of is_a? This method of Object handily tells us if a variable is an instance of a particular class.
url = options.is_a?(String) ? options : url_for(options)
Much nicer than the alternative:
url = (options.class == String) ? options : url_for(options)
Subclasses
In fact, is_a? goes way beyond this. It also works for subclasses, so for example:
class Mammal
end
class Horse < Mammal
end
Horse.new.is_a? Horse
# => true
Horse.new.is_a? Mammal
# => true
Horse.new.is_a? Object
# => true
Modules
is_a? also applies to included modules, so we can do:
module Mount
end
class Horse
include Mount
end
Horse.new.is_a? Mount
# => true
Returning to the helper
We can see that we’re testing if options is a String. If it is, the helper treats it as a URL. If not, it chucks it up to url_for.