I’ve been trying to update a Rails 6 app to Rails 7 and was having fairly good results until I ran into classic scaffold delete links. I sense that JS alert aren’t vogue anymore, but I’ve clicked on the wrong button or link too many times to allow an inadvertent click destroy something by mistake.
An older post had a few suggestions but with way more javascript than I wanted to deal with. I’m just a Stimulus person which I am soooo happy it came along. So I wrote a short Stimulus controller that was similar to one in the older post to deal with the button_to
hidden form.
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = [ "submit"]
static values = { cmsg: String}
connect() {
// console.log("destroy confirm")
// set default confirm_msg
if (this.hasCmsgValue) {
this.confirm_msg = this.cmsgValue
}else{
this.confirm_msg = "Are you sure?"
}
}
confirm(){
// console.log(this.submitTarget.closest('form'))
let ans = confirm(`${this.confirm_msg}`)
if (ans == true) {
this.submitTarget.closest('form').submit()
}
}
}
The current Rails 7 scaffold button-to helper (with tailwind.css):
<div class="inline-block ml-2">
<%= button_to 'Destroy this entry', entry_path(@entry), method: :delete, class: "mt-2 rounded-lg py-3 px-5 bg-gray-100 font-medium" %>
</div>
Generates the hidden form:
<div class="inline-block ml-2">
<form class="button_to" method="post" action="/entries/1"><input type="hidden"
name="_method" value="delete" autocomplete="off">
<button class="mt-2 rounded-lg py-3 px-5 bg-gray-100 font-medium" type="submit">
Destroy this entry
</button>
<input type="hidden" name="authenticity_token"
value="zsLeEqDkcTJdNc0IPyFaFlEvSaZLQv_HD8riMdLJfwY_vCB6H5rXARAzarIl9MevstETykLn7ne3bNB8yMeyjQ" autocomplete="off">
</form>
</div>
I then wrapped that div/button in another div along with Stimulus stuff (slim-rails) and some options
div[class="#{btnDanger} inline-block"
data-controller="destroyConfirm"
data-action="click->destroyConfirm#confirm"
data-destroyConfirm-cmsg-value="A longer version of Are You Sure?"]
span Delete Entry
= button_to '',@entry, method: :delete,
class:"hidden",
data:{destroyConfirm_target:"submit"}
Clicking on the outer div button, calls the controller and asks for confirmation. If yes, it submits the closest form (the hidden form) that delete the object.
That a lot of typing, but then I can add a rails helper that has default options:
def destroyConfirmTag(model,confirm_msg:"",klass:"",prompt:"")
klass= "#{btnDanger} inline-block" if klass.blank?
confirm_msg = "Are You Sure?" if confirm_msg.blank?
prompt = "Delete #{model.class.name}" if prompt.blank?
node = content_tag(:div, class: klass,
data:{
controller:"destroyConfirm",
action:"click->destroyConfirm#confirm",
destroyConfirm_cmsg_value:confirm_msg
}){
concat(tag.span(prompt))
concat(button_to( '',model, method: :delete,class:"hidden",data:{destroyConfirm_target:"submit"}))
}
node
end
Now I only have to type: = destroyConfirmTag(@entry)
into the view for my delete tag.
If your using icons (e.g. fontawsome), rather than a button you can do something like:
= destroyConfirmTag(deposit,
klass:"inline-block mr-4",
prompt:tag.i(class:"fas fa-trash w3-text-red"))
I’ll mention that btnDanger
is just another helper that return my standard class so you can customize it to your theme.