Skip to content

Instantly share code, notes, and snippets.

@mmrwoods
Last active December 19, 2015 00:09
Show Gist options
  • Save mmrwoods/5866233 to your computer and use it in GitHub Desktop.
Save mmrwoods/5866233 to your computer and use it in GitHub Desktop.
Make formtastic's cancel action return the user to the original referrer
# Make formtastic's cancel action return the user to the original referrer
#
# By default, the cancel action in formtastic always goes to the previous
# page, so hitting cancel after validation failures returns the user to
# the form, not the original referring page. The code below modifies the
# cancel action such that it by default returns to the original referrer.
# It does so by simply keeping track of the referrer in a hidden field.
#
# See also https://github.com/justinfrench/formtastic/issues/780
require 'formtastic'
Formtastic::Actions::LinkAction.class_eval do
def to_html
wrapper do
hidden_field_html + template.link_to(text, url, button_html)
end
end
def url
return options[:url] if options.key?(:url)
hidden_field_value || :back
end
private
def hidden_field_name
"#{object_name}_#{method}_action_url"
end
def hidden_field_value
return unless template.respond_to?(:params) && template.params[hidden_field_name].present?
deserialize_url(template.params[hidden_field_name])
end
def hidden_field_html
# note: encode url when writing to hidden form field to avoid false positives for remote file inclusion attacks
return "".html_safe if options.key?(:url)
template.hidden_field_tag(hidden_field_name, serialize_url(template.url_for(url)))
end
def serialize_url(value)
# note: encode url as cgi query string to avoid false positives for xss attacks when using json
ActiveSupport::JSON.decode(URI.parse(value).to_json).to_query
end
def deserialize_url(value)
# build url from cgi query value
URI::Generic.build(
CGI.parse(value).tap do |h|
# CGI.parse generates an array of values for each key, we just want the first
h.each{|k,v| h[k] = v.first}
# convert strings that represent integers to integers (e.g. port number)
h.each{|k,v| h[k] = v.to_i if v.match(/^[0-9]+$/)}
# convert empty strings to nil
h.each{|k,v| h[k] = nil if v.blank?}
end.symbolize_keys
).to_s
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment