The feature request said: Create a mechanism whereby a user will be notified when an administrator suspends their account... and further... ensure that the administrator inputs a reason for the suspension. And include that reason in the notification email to the user..
So.. I thought to myself... sure... lets not stop at merely asking the administrator if they are sure about what they're doing when they press that shiny red button that makes the database row magically implode... Lets go a step further and ask the user why they want to press the shiny red candy-like button... that makes the record to vanish in a fiery ball of liquid hot mag-ma.
I thought about this issue for a few moments and decided:
- I want this to be as painless as possible to implement (i mean retarded-simple)... i need to be able to do this after a long morning of skulling Irish coffee...
- I want to be able to seriously annoy my users and administrators by asking them to explain themselves for every single action they ever do... (not that I would... but I could)
- I don't want to have to overload actions or create duplicate actions for every single explainable action in the system... (after all, duplicating work means i have to type that much more... or hit command-c, command-v alot... and how much fun is that... really?)
- It would be a huge bonus if this was as easy as link_to :confirm=>'blah blah'
So, in a brief brain dump with my coworkers... somebody (the boss... this is probably why he's the boss)... says in a moment of pure brilliance... use a javascript prompt...
To which i scratched my head... and thought way back to those yonder days of yore... yes, there were alert-style pop-ups that contained text inputs... (that was way-way-back in the days of never-ending q&a sessions with a pre-programmed script... the great-grandfather of being rick-rolled)... i've not seen one of those in a long time... it's crazy... but it just might work...
But wait... Seriously... i figured that somebody else had surely done this already... like maybe the rails core team... surely such basic function already existed... right... I mean, those guys that write this stuff think of everything, don't they?
Seriously... no sarcasm meant in that line... really... nine out of ten times i start doing anything in ruby these days i come to realize that somebody else has already done it... and usually done it far better than i was planning to... so... I scan the API docs, do some serious Googling and eventually scan the source code for link_to... and verify as best i can that nobody has done this yet...
Thinking that nobody has ever done this... This sometimes makes me nervous (like any time i have this feeling... i start to question my motives)... if nobody else has done it... does that mean there is a good reason... has nobody ever needed it... or maybe, like genetic manipulation... maybe it's better that we don't do it... but i think i'm getting a little off track here...
FUH--CUS... EV-A-RAY BODDY MUST FUH-KUS
After much source code tracing and digestion the three simple methods below crafted into a strategically placed barrel-of-monkey-patch will have your rails link_to method capturing that extra explanation string and passing in on through to your controller so you can decide what to do with it... i.e. Email the user whose account just got suspended that they won't be able to log in anymore... or whatever you want... the possibilities are truly limitless.
The beauty is: you get all this using the same conventions you already use.. that is assuming 'you' are my fellow ruby on rails coders and 'you' do things like i do... i know it'a stretch... but ya never know...
link_to 'my Action', action_url, :prompt=>'why do you want to do this?'
This little gem will confront your user with a nifty javascript alert with a string input and will refuse to pass go until the user has entered an excuse for their request. Additional validation on the supplied string should be done server-side and perhaps a flash message and redirect tells the user their excuse wasn't up to snuff..
And i do suppose it's important to mention that the supplied reason will be posted in to your controller action in the form or params[:prompt_reply] ...
Hooray for perpetuating the everlasting nag-screen!!!
And for those of you have been ever-so-patient and read this far i give you... the code... and better yet... forget the code... i mixed this into a simple plugin... snag it from github. http://github.com/bhedana/link_to_with_prompt/
module ActionView
module Helpers
module UrlHelpers
def convert_options_to_javascript!(html_options, url = '')
prompt, confirm, popup = html_options.delete("prompt"), html_options.delete("confirm"), html_options.delete("popup")
method, href = html_options.delete("method"), html_options['href']
html_options["onclick"] = case
when popup && method
raise ActionView::ActionViewError, "You can't use :popup and :method in the same link"
when confirm && popup
"if (#{confirm_javascript_function(confirm)}) { #{popup_javascript_function(popup)} };return false;"
when confirm && method
"if (#{confirm_javascript_function(confirm)}) { #{method_javascript_function(method)} };return false;"
when confirm
"return #{confirm_javascript_function(confirm)};"
when prompt
method ||= :post
"#{prompt_javascript_function(prompt)}"+
"if(prompt_reply) { #{send_prompt_javascript_function(method, url, href)} }; return false;"
when method
"#{method_javascript_function(method, url, href)}return false;"
when popup
"#{popup_javascript_function(popup)} return false;"
else
html_options["onclick"]
end
end
def prompt_javascript_function(prompt)
"var prompt_reply = prompt('#{escape_javascript(prompt)}');"
end
def send_prompt_javascript_function(method, url = '', href = nil)
action = (href && url.size > 0) ? "'#{url}'" : 'this.href'
submit_function =
"var f = document.createElement('form'); f.style.display = 'none'; " +
"this.parentNode.appendChild(f); f.method = 'POST'; f.action = #{action}; "+
"var p = document.createElement('input'); p.setAttribute('type', 'hidden'); p.setAttribute('name', 'prompt_reply'); p.setAttribute('value', prompt_reply); f.appendChild(p);"
unless method == :post
submit_function << "var m = document.createElement('input'); m.setAttribute('type', 'hidden'); "
submit_function << "m.setAttribute('name', '_method'); m.setAttribute('value', '#{method}'); f.appendChild(m);"
end
if protect_against_forgery?
submit_function << "var s = document.createElement('input'); s.setAttribute('type', 'hidden'); "
submit_function << "s.setAttribute('name', '#{request_forgery_protection_token}'); s.setAttribute('value', '#{escape_javascript form_authenticity_token}'); f.appendChild(s);"
end
submit_function << "f.submit();"
end
end
end
end