Change action attribute of form using JavaScript in Rails

Hello everyone,

I had a situation where I've more than one submit buttons in a form
which I need to send data to different controllers' action. From my
previous posts I got a suggestion to use JavaScript.

**Please Note: I'm not looking forward to detect which button is pressed
and redirect according to it.

Here is my code.

view
<%= form_tag "#", :id => "multi_cont_form" do %>
       <div class="field">
  <%= label_tag("From date") %>
  <%= date_field_tag 'fdate', Date.today, :autofocus =>true, class:
'form-control' %>
       </div>

       <div class="actions">
        <%= button_tag "Test JS", :onclick =>
"sendParams('receipt_rpts_create_path')" %>
       </div>

       <div class="actions">
  <%= button_tag "Test JS", :onclick =>
"sendParams('payments_rpts_create_path')" %>
       </div>
<% end %>

(I've only showed two buttons for example purpose.)

JavaScript

function sendParams(newAction)
{
  var mem_code = document.getElementById("member_code").value;
  var x = document.getElementById("multi_cont_form").action;
  document.getElementById("multi_cont_form").setAttribute("action", "");
  console.log("Checking form action received " + newAction + "..");
  console.log("Current form action " + x + "..");
  document.getElementById("multi_cont_form").setAttribute("action",
"http://www.localhost:3000/receipt_rpts_create_path");
  var x = document.getElementById("multi_cont_form").action;
  console.log("New action " + x + "..");
  alert("New action of form is " + x);
  document.getElementById("multi_cont_form").submit();
}

Even after I reset action attribute to "" and reassigned with new given
action, the final URL is being prefixed with current page's URL.

For eg:
If current page URL is "localhost:3000/reports/new"
The newly created form action using JS is
"localhost:3000/reports/receipt_rpts_create_path"

I can't prevent that "reports" from being prefixed.
And even "receipt_rpts_create_path" is not converted to
receipt_rpts/create URL.

Technically how to change "controller" option's value and "action"
option's value of <% form_tag %> helper using JavaScript. If its not
possible how to achieve it using JS.

Hello everyone,

I had a situation where I've more than one submit buttons in a form
which I need to send data to different controllers' action. From my
previous posts I got a suggestion to use JavaScript.

**Please Note: I'm not looking forward to detect which button is pressed
and redirect according to it.

Here is my code.

view
<%= form_tag "#", :id => "multi_cont_form" do %>
      <div class="field">
<%= label_tag("From date") %>
<%= date_field_tag 'fdate', Date.today, :autofocus =>true, class:
'form-control' %>
      </div>

      <div class="actions">
       <%= button_tag "Test JS", :onclick =>
"sendParams('receipt_rpts_create_path')" %>
      </div>

      <div class="actions">
<%= button_tag "Test JS", :onclick =>
"sendParams('payments_rpts_create_path')" %>
      </div>
<% end %>

(I've only showed two buttons for example purpose.)

JavaScript

function sendParams(newAction)
{
var mem_code = document.getElementById("member_code").value;
var x = document.getElementById("multi_cont_form").action;
document.getElementById("multi_cont_form").setAttribute("action", "");
console.log("Checking form action received " + newAction + "..");
console.log("Current form action " + x + "..");
document.getElementById("multi_cont_form").setAttribute("action",
"http://www.localhost:3000/receipt_rpts_create_path");
var x = document.getElementById("multi_cont_form").action;
console.log("New action " + x + "..");
alert("New action of form is " + x);
document.getElementById("multi_cont_form").submit();
}

Even after I reset action attribute to "" and reassigned with new given
action, the final URL is being prefixed with current page's URL.

This signals to me that your new action does not begin with a / or a http(s)://.

This is normal browser behavior.

If you assign a fully-qualified URL or a complete (root-relative) path to either an a#href or form#action, the browser will accept that. But if your new URL or path is not complete, then the browser will attempt to "canonicalize" it by adding the current context to it.

Walter

This signals to me that your new action does not begin with a / or a
http(s)://.

This is normal browser behavior.

If you assign a fully-qualified URL or a complete (root-relative) path
to either an a#href or form#action, the browser will accept that. But if
your new URL or path is not complete, then the browser will attempt to
"canonicalize" it by adding the current context to it.

Walter

Hello Walter, it does begin with http://. Another weird thing is if
current URL is localhost..../reports/new, It only discards "/new" part
but keeps "/reports" part. After some time I got to know that "/reports"
is controller and "/new" is action. That's why I want to change
controller dynamically. And as rails converts <% form_tag %> hash to a
valid URL its not converting JS supplied URL.

But I'm OK if I have to use fully qualified URL but need some help with
how I have to tell rails to match that URL to a controller's action.
Finally all I want is to change both controller and action using
JavaScript(which may not possible at all because "controller" hash is of
form_tag helper). Or a workaround equivalent to this.

Thank you.

This signals to me that your new action does not begin with a / or a
http(s)://.

This is normal browser behavior.

If you assign a fully-qualified URL or a complete (root-relative) path
to either an a#href or form#action, the browser will accept that. But if
your new URL or path is not complete, then the browser will attempt to
"canonicalize" it by adding the current context to it.

Walter

Hello Walter, it does begin with http://. Another weird thing is if
current URL is localhost..../reports/new, It only discards "/new" part
but keeps "/reports" part. After some time I got to know that "/reports"
is controller and "/new" is action. That's why I want to change
controller dynamically. And as rails converts <% form_tag %> hash to a
valid URL its not converting JS supplied URL.

But I'm OK if I have to use fully qualified URL but need some help with
how I have to tell rails to match that URL to a controller's action.
Finally all I want is to change both controller and action using
JavaScript(which may not possible at all because "controller" hash is of
form_tag helper). Or a workaround equivalent to this.

Once the HTML is in the page, and JavaScript is working on it, the form_tag helper has nothing more to say about it. form_tag is Ruby that writes HTML. JavaScript acts on that HTML and modifies the DOM in the browser -- Ruby is all done at that point.

I suspect now that the issue may be in your JavaScript. I know this technique works, because I wrote something that did exactly what you describe not too long ago. I don't have it in front of me, but the basic idea was to add data- attributes to the various buttons, and then register a click handler to use that data- attribute as the form's Action. Off the top of my head, something like this:

$(document).on('click', 'input[data-action]', function(){
  $(this).closest('form').attr('action', $(this).data('action'));
});

If that doesn't work, then the handler may have to be registered on the form's submit method instead, but I think that the click on the button will register and complete before the form within it gets the message to submit itself.

To set up that data attribute, you would simply add it to the f.submit helper like this:

<%= f.submit data: { action: '/some/complete/route' } %>

Walter

Hello Walter,
It was a simple mistake I had done in form that I’m laughing at myself now.

Instead of giving :onclick => “sendParams(‘receipt_rpts/create’)”

I should have gave :onclick => “sendParams(’/receipt_rpts/create’)”

It was just a slash “/” I should have given before the URL. Then the controller name “/reports” won’t get prefixed automatically.

And another code :onclick => “sendParams(‘receipt_rpts_create_path’)” is completely wrong as you said, if this type of path has mentioned inside rails then rails would have already converted those helper and hash before page is rendered and JS will access only decoded HTML. So all I have to give is decoded path.

Hello Walter,
It was a simple mistake I had done in form that I'm laughing at myself now.
Instead of giving :onclick => "sendParams('receipt_rpts/create')"
I should have gave :onclick => "sendParams('/receipt_rpts/create')"

It was just a slash "/" I should have given before the URL. Then the controller name "/reports" won't get prefixed automatically.

And another code :onclick => "sendParams('receipt_rpts_create_path')" is completely wrong as you said, if this type of path has mentioned inside rails then rails would have already converted those helper and hash before page is rendered and JS will access only decoded HTML. So all I have to give is decoded path.

Thank you for your help.

You are welcome, glad you figured it out.

Walter