How to make Rails 5.2 form submit remotely? - ruby-on-rails

In my view, using Slim:
= form_with url: update_pn_price_path(#price)
.form-group
= label_tag :part_number
= text_field_tag :part_number, #price.part_number, required: true
.form-group
=> submit_tag t(:save), class: 'btn btn-primary btn-sm'
= link_to 'Cancel', '', class: 'btn btn-link btn-sm', data: { cancel_in_place: true }
This always submits using a standard submit, not remotely. Log shows:
Processing by PricesController#update_pn as HTML
What am I doing wrong? Why won't it submit using JS?

I'm surprised to see that your view compiles. There are a few problems that I can spot.
You start indenting content as though it would be in the form. However you didn't open a form tag or provided a block to the form_with method.
= form_with url: update_pn_price_path(#price)
.form-group
Should at least be changed to:
= form_with url: update_pn_price_path(#price) do
.form-group
Since a variable is provided to a block, the preferred way is to capture it in a variable (form in the code below). If you're not planning to use it you should still capture it in an underscored variable to indicate that it is there, but not being used (_form).
= form_with url: update_pn_price_path(#price) do |form|
.form-group
Since you're using a form builder, the preferred way of creating elements is through the form builder interface. Since you're not creating the submit tag through the form builder this might be another reason why the submit isn't done remotely.
I would at least replace:
=> submit_tag t(:save), class: 'btn btn-primary btn-sm'
With:
= form.submit t('save'), class: 'btn btn-primary btn-sm'
But preferably update the whole form to use the form builder. The result should look something like this:
= form_with model: #price, url: update_pn_price_path(#price) do |form|
.form-group
= form.label :part_number
= form.text_field :part_number, required: true
.form-group
= form.submit t('save'), class: 'btn btn-primary btn-sm'
= link_to 'Cancel', '', class: 'btn btn-link btn-sm', data: {cancel_in_place: true}
For more/other form builder methods see the FormBuilder and FormHelper documentation.

Here's what solved the issue. Rookie mistake, but posting here in case someone else runs into it.
My form shown above was inside another form. You can submit such an 'inner' form, but not remotely. The form was being inserted via an AJAX call, so I changed that to insert to the end of the HTML body, and then positioned using CSS. That put it outside the containing form and made things work as expected.

Related

Rails 'remote:true' ignored when params provided

In a Rails (5.2.4.2) app
I am using button_to + remote: true, and this is working as expected -> ajax call fired, all is OK.
But then I add 'params' to the button_to. Params are added to the form as hidden input (as expected) but when I click on the button, the request made is not remote, and all the page content is updated.
Problematic: button_to + remote + params -> this code seems to ignore the remote:true, although I see data-remote="true" in the form tag
<%= button_to ent_path(ent),
{remote: true,
method: :patch,
class:"btn btn-primary",
params: {ent: {active_a: false}}
} do
%>
<span>TEEEST</span>
<% end %>
Working as expected:
<%= button_to ent_path(ent),
{remote: true,
method: :patch,
class:"btn btn-primary",
} do
%>
<span>TEEEST</span>
<% end %>
So my purpose is to have the button_to remote and update the ent record, changing the active_a attribute depending on some logic
You want to pass any extra parameters via the link path, like this
<%= button_to ent_path(ent, active_a: false),
{remote: true,
method: :patch,
class:"btn btn-primary",
} do
%>
<span>TEEEST</span>
<% end %>
Turned out the remote:true was working properly. But there was a redirect_back in the controller that was executed in case of some custom logic, so that appeared as if the button is working without remote:true

Rails parameters contain backslashes

I am currently working with button_tag to create a remote styled answer submission quiz. When pressing this button, instead of posting the new record, it is throwing an error.
ActiveRecord::RecordNotFound (Couldn't find Answer without an ID):
When looking at the server logs I see it is trying to work with these params when trying to post Parameters: {"{\"answer_id\":59}"=>nil, "id"=>"15"}
What I am looking, or expecting to see is this.
Parameters: {"answer_id"=>"59", "id"=>"15"}
Here is the button_tag I am using.
<% #question.answers.each do |answer| %>
<%= button_tag "#{answer.answer.titleize}", class: 'btn btn-block btn-lg btn-primary', data: {
remote: true,
method: :post,
url: answer_question_path(#question),
params: { answer_id: answer.id }
} %>
<% end %>
Here is my response controller which is responsible for submitting the POST request.
class ResponsesController < ApplicationController
def answer
question = Question.find(params[:id])
answer = question.answers.find(params[:answer_id])
response = question.responses.find_or_initialize_by(user: current_user)
if response.update(answer: answer)
head :ok
else
puts 'Something went wrong chief'
end
end
private
def responses_params
params.require(:response).permit(:user_id, :question_id, :answer_id)
end
end
I have tried using to_json on the parameter with no success and have not been able to find any solution elsewhere on SO or other forums. Any ideas?
This seems to be an issue with button_tag in the feature I am using it for.
button_tag creates a button element that defines a submit button, resetbutton or a generic button which can be used in JavaScript. button_tag is also an action view helper but is defined as a FormTagHelper.
button_to generates a form containing a single button that submits to the URL created by the set of options. button_to is a UrlHelper while button_tag is a ViewHelper.
Below is the button_tag code I was using which was creating the issue described above. Using button_tag fixed my parameters issue and also looks a bit cleaner. I hope this helps anybody else having issues with button_tag in the future.
<%= button_tag "#{answer.answer.titleize}", class: 'btn btn-block btn-lg btn-primary', data: {
remote: true,
method: :post,
url: answer_question_path(#question),
params: { answer_id: answer.id }
} %>
<%= button_to "#{answer.answer.titleize}",
answer_question_path(#question),
class: 'btn btn-block btn-lg btn-primary',
params: { answer_id: answer.id },
remote: true %>

Passing variable from view to controller Rails 4

I want to pass one variable which is introduced by the user in the front-end. I dont use any model (i dont need it, because im working with JSON data all in memory). I have looked many tutoriasl but almost all of them are focused on filling out a form. My application does not have any form nor tables. Any idea?
Thank you.
{<div class="module1">
<p>Mein Lastprofil berechnen</p>
<div class="boxed">
Jahreshausverbrauch (kWh)
<%= text_field_tag "input", nil, placeholder: "3500" %>
<%= button_to "Senden", root_path, :method => :get %>
</div>
</div>}
I want to save/pass the variable introduced when clickling the button.
By having a text field you implicitly already have a form.
Make it explicit by wrapping the text field and button:
<%= form_tag root_path, method: :get do %>
<%= text_field_tag :input, placeholder: "3500" %>
<%= submit_tag "Senden" %>
<% end %>
Then you can access the value as params[:input] in the controller.

How to stop button being passed with parameters?

I don't know why all of my form's buttons and submits keep passing the button in the Parameters also. An example would be If I use my search form and put in the word "Testing". The result I will get is below:
# Using Bootstrap 3.2.0 and Rails 4.1.1
= form_tag products_path, method: :get do
.input-group
= text_field_tag :query, params[:query], class: 'form-control'
%span.input-group-btn
= button_tag(type: 'submit', class: 'btn') do
Search
Parameters: {"utf8"=>"✓", "query"=>"Testing", "button"=>""}
How can I make it not do that?
The name attribute of button is "button" by default.
You could set it to nil by:
= button_tag(type: 'submit', class: 'btn', name: nil) do

Rails 3 submit form with link

How I can submit form with link on correct rails 3 format?
Thanks.
<%= form_for #post do |f| %>
<%= f.label :title %><br>
<%= f.text_field :title %>
<p><%= f.submit %></p>
<% end %>
My code sample.
For people who came here via Google, I have an improvement on Zequez's answer. Instead of the method that he gives, add this method to the application helper instead:
def link_to_submit(*args, &block)
link_to_function (block_given? ? capture(&block) : args[0]), "$(this).closest('form').submit()", args.extract_options!
end
Then, as Zequez stated, for simple links you can just do this in your view:
<%= link_to_submit 'Submit Form' %>
...and for more complicated buttons you can pass HTML options and a block to be used inside the link. If you use Twitter Bootstrap, for example, this lets you add CSS classes, formatting and icons:
<%= link_to_submit( class: 'btn btn-primary' ) do %>
<strong>Submit</strong> the Form <i class="icon-arrow-right"></i>
<% end %>
The JQuery code will work as long as the link is a child of the form (that is, as long as link_to_submit is called from somewhere within the form_for block).
"Correct" is a tricky word in this context ;) . One could ask why you're not just taking a button element and make it look like a link?
Anyways — you can't achieve this with plain HTML (at least not to my knowledge). With a Javascript framework like e.g. jQuery you could simply do something like this:
$('a').click(function(){
$('form').submit();
return false;
});
Rails 2.3.x had a link_to_remote helper which let's you specify a :submit parameter (= DOM element's ID, default is the parent form). So you were be able to write:
link_to_remote 'submit', :url => {…}, :submit => "my_form"
But with Rails 3's push to UJS, this helper is gone.
You can add the following to the application helper:
def link_to_submit(text)
link_to_function text, "$(this).closest('form').submit()"
end
Then inside your view files you can just call
link_to_submit 'Submit Form'
And the link must be child of the form.
With jquery, this one-liner will work fine for a simple form.
<%= link_to t("translate.submit"), "#", class: "make it beautiful", :onclick=>"$('form').submit()" %>
Of course you don't really have to use jquery, just finding the dom element for your form will work fine as well.
<%= link_to t("translate.submit"), "#", class: "make it beautiful", :onclick=>"document.getElementById('your_form_id').submit()" %>
This way you don't use any ajax, just plain form submit.
In Rails 3, the link_to_remote helper is gone, but it's replaced with
link_to 'submit me', url_for(#post), {:remote => true, :class => 'submit_me'}
In your case, you likely want your form to do the AJAX, like so:
<%= form_for #post, :remote => true do |f| %>
<%= f.label :title %><br>
<%= f.text_field :title %>
<p><%= f.submit %></p>
<% end %>
With a companion link:
link_to 'submit me', '#', :class => 'submit_me'
Then, in an .js file included in the page body:
$('.submit_me').click(function() {
$('form').submit();
return false;
});
The idea is that anything more complicated than turning a link or form into an ajax request should be done with the jQuery callbacks, as listed here:
https://github.com/rails/jquery-ujs/wiki/ajax
And if you want to really get into interactive AJAX requests, go here for a great 2-part article on it.

Resources