Skip to content

Instantly share code, notes, and snippets.

@xhocquet
Created April 2, 2019 03:20
Show Gist options
  • Save xhocquet/8b58685ac4d97177e960be2fda044f08 to your computer and use it in GitHub Desktop.
Save xhocquet/8b58685ac4d97177e960be2fda044f08 to your computer and use it in GitHub Desktop.
module ActiveLinkTo
extend ActiveSupport::Concern
included do
helper_method :active_link_to
def active_link_to(name = nil, options = nil, html_options = nil, &block)
html_options, options, name = options, name, block if block_given?
options ||= {}
html_options = convert_options_to_data_attributes(options, html_options)
url = url_for(options)
html_options["href".freeze] ||= url
if url == request.path
existing_class = html_options["class".freeze] ||= ""
new_class = "#{existing_class} active"
html_options["class".freeze] = new_class
end
view_context.link_to(name, options, html_options, &block)
end
private
def convert_options_to_data_attributes(options, html_options)
if html_options
html_options = html_options.stringify_keys
html_options["data-remote"] = "true".freeze if link_to_remote_options?(options) || link_to_remote_options?(html_options)
method = html_options.delete("method".freeze)
add_method_to_attributes!(html_options, method) if method
html_options
else
link_to_remote_options?(options) ? { "data-remote" => "true".freeze } : {}
end
end
def link_to_remote_options?(options)
if options.is_a?(Hash)
options.delete("remote".freeze) || options.delete(:remote)
end
end
def add_method_to_attributes!(html_options, method)
if method_not_get_method?(method) && html_options["rel"] !~ /nofollow/
if html_options["rel"].blank?
html_options["rel"] = "nofollow"
else
html_options["rel"] = "#{html_options["rel"]} nofollow"
end
end
html_options["data-method"] = method
end
STRINGIFIED_COMMON_METHODS = {
get: "get",
delete: "delete",
patch: "patch",
post: "post",
put: "put",
}.freeze
def method_not_get_method?(method)
return false unless method
(STRINGIFIED_COMMON_METHODS[method] || method.to_s.downcase) != "get"
end
def token_tag(token = nil, form_options: {})
if token != false && protect_against_forgery?
token ||= form_authenticity_token(form_options: form_options)
tag(:input, type: "hidden", name: request_forgery_protection_token.to_s, value: token)
else
"".freeze
end
end
def method_tag(method)
tag("input", type: "hidden", name: "_method", value: method.to_s)
end
# Returns an array of hashes each containing :name and :value keys
# suitable for use as the names and values of form input fields:
#
# to_form_params(name: 'David', nationality: 'Danish')
# # => [{name: 'name', value: 'David'}, {name: 'nationality', value: 'Danish'}]
#
# to_form_params(country: {name: 'Denmark'})
# # => [{name: 'country[name]', value: 'Denmark'}]
#
# to_form_params(countries: ['Denmark', 'Sweden']})
# # => [{name: 'countries[]', value: 'Denmark'}, {name: 'countries[]', value: 'Sweden'}]
#
# An optional namespace can be passed to enclose key names:
#
# to_form_params({ name: 'Denmark' }, 'country')
# # => [{name: 'country[name]', value: 'Denmark'}]
def to_form_params(attribute, namespace = nil)
attribute = if attribute.respond_to?(:permitted?)
attribute.to_h
else
attribute
end
params = []
case attribute
when Hash
attribute.each do |key, value|
prefix = namespace ? "#{namespace}[#{key}]" : key
params.push(*to_form_params(value, prefix))
end
when Array
array_prefix = "#{namespace}[]"
attribute.each do |value|
params.push(*to_form_params(value, array_prefix))
end
else
params << { name: namespace.to_s, value: attribute.to_param }
end
params.sort_by { |pair| pair[:name] }
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment