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
Related
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 %>
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.
I have a method like this:
gamer.rb
def approve_gamer(type)
where(type: type).last.update(status: 'approved')
end
and I want to make a button for each type to call approve_gamer('type').
Should it be button_to [:approve_gamer, gamer] or link_to ... class: "btn btn-default"? How do I pass the type parameter there?
I'd use the button_to helper since I wouldn't call data-changing methods through GET.
button_to creates a form around the button and sends the data through POST.
More to read here: http://apidock.com/rails/ActionView/Helpers/UrlHelper/button_to
You can also set the form yourself:
<%= form_for gamer, :url => { :action => 'approve' } do |f| %>
<%= f.hidden_field('type', :value => type_goes_here) %>
<%= button_tag 'Approve', class: 'btn btn-default' %>
<% end %>
That method you call should be in your gamers_controller though.
Also you could simply call the edit method for gamer and set the parameters.
And if you call the method approveyou have to set the route, too.
Here's my form:
<%= form_for #asset do |f| %>
<%= f.check_box :remove_picture %>
<%= f.submit "Remove" %>
<% end %>
How could I just make this one button that does :remove_picture and submit? Thanks
Check out the API dock for the form_for helper:
http://apidock.com/rails/ActionView/Helpers/FormHelper/form_for
You can force the form to use the full array of HTTP verbs by setting
:method => (:get|:post|:put|:delete)
So your code might look like
<%= form_for(#asset, html: { method: :delete }) do |f| %>
<%= f.submit "Remove" %>
<% end %>
You could change the checkbox to a hidden field on the form...
If it were me, I'd look at something like button_to and handle this via AJAX on the controller. This way the button would call a controller action, say remove_picture and return a JS response which could update your view.
Example:
button_to([remove_picture, #asset], { method: :delete })
Note: method: :delete may not be needed - depends on your routes.
hy, i'm trying to update a single field in a user resouce. The field to update is 'locale', it is a string type.
i have triend with a form and it works:
<%= form_for current_user do |f| %>
<%= f.select :locale, [['En', 'en'], ['It', 'it']] %>
<%= f.submit %>
<% end %>
now i'm trying to update the same field using a link or a button:
<%= current_user.locale = 'fr' %>
<%= button_to "update" ,current_user,method: :patch %>
<%= button_to "update" ,user_path(current_user),method: :patch %>
but none of this work.
the problem is the request, infact the web server doesn't recive the current_user parameters:
{"_method"=>"patch",
"authenticity_token"=>"7X6QdD4DGxsXaETT86/8Ut4xyuOICaxirs4IjmZl7jY=",
"locale"=>"en",
"id"=>"1"}
There is no current_users parameters.
i have tried with the link_to but the problem is the same:
<%= link_to "update", current_user ,method: :patch %>
I have no idea. Can you help me?
The fact that you don't get the parameter sent back to server is the expected one since you don't use a form.
In order to pass the parameter back you have to:
use a form (as you did) or
pass the parameter in the url of the button: button_to 'update', user_path(param_name: 'param_value')
In the second case, you will have to search for the appropriate parameter in your action, ex params[:param_name]