The other day I had created a form without a submit button. It is a simple checkbox, which toggles if a user is admin for a project.
It looks like this:
Ticking the box should toggle the state for the user. So I created a controller action:
1 2 3 4
ProjectAdministrationPolicy is about authorization. I use the
Pundit gem for these tasks.
ProjectAdministration.toggle!(params[:user_id], @project.id) toggles the
admin? state for the given user. I return a boolean representing the outcome of
the action. Perhaps there was an error of some kind, or the
allowed to change the admin state for the given user. Either way we get a
true/false result, which we use in our view.
There are two views at play here. The first is the view with the form itself. The other view is what gets rendered after the form was submitted. Let’s start with the view that contains the form.
1 2 3 4 5
The important parts of the form are the options to the form itself.
:post makes sure, we use the right HTTP action.
remote: true makes this a
standard rails form tags. A little trick you’re perhaps not aware of: If you use
checkboxes in your form, the checkbox’ value only gets submitted, if it is
checked. We need the value (the user id) all the time, to actually find the
user and toggle its admin state. That’s why we always submit the user_id
using a hidden_field. This makes sure, we always have the value, no matter the
state of the checkbox.
1 2 3 4 5 6 7 8 9
This adds a
<div> at the top of the page, just below the topbar.
This is where I show my warnings and notices. It’s of course up to you to
decide where you want to show this flash message. Or you don’t show it at all.
The last three lines set a timeout of 1.5 seconds. After the countdown completes the warning or notice is hidden with a little animation, courtesy of jQuery. I set the speed for the hide animation to 400ms.
As we use
toggle_admin_state_path in our form, and because we defined the
controller action, we need to set up a route for this to work. That’s easy:
Submitting the form
The final step is submitting the form. The naive way (read: the way I tried first)
is to use an event handler and just call
submit() on the form. It may look like this:
This actually works. Only problem is, it’s not submitted as JS, but as HTML:
If you want to submit as a truely remote form, and use your
.js.erb view, you
have to do things a little differently.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
Let’s take it from the top:
Line 1 binds to the change event of this checkbox. If you check or uncheck it, the function is called.
Line 2 uses jQuery to make an asynchronous HTTP request
Line 3 the url for the request
These were basic options. Now we have to set the correct headers.
Line 5 Set the
accept header. By default it depends on the
dataType. But if you set the
POST request get submitted as a
GET request. Which doesn’t work for us.
Line 6 Set the content-type. This is important. Otherwise your form parameters won’t be submitted in a way that your server understands and processes them.
Line 8 make sure this is a
Line 9 get the form data and set it as request data (body)
Now if we toggle the checkbox, the request is sent as a JS request:
This wraps it up. I hope you’re successful with your remote forms. This time there won’t be a Github repository. The content of this post is quite specific to my app. I believe you can implement your remote forms quite easily wih the right jQuery asynchronous HTTP request syntax.