Rails not using correct controller method - ruby-on-rails

I got a view with the following code:
<%= form_for(#stock,:url=>{:action=>"buyback"},:html=>{:class=>"form-horizontal"}) do |f| %>
My routes.rb file shows:
post '/stocks/buyback'
When I click the submit button of the form, it does not trigger the method buyback of the controller but instead update.
The log file shows:
Started PUT "/stocks/buyback" for 127.0.0.1 at 2012-07-22 19:46:07 +0800
Processing by StocksController#update as HTML
Its triggering the controller method Update instead of buyback. Why?

try this
<%= form_for(#stock,:url=>{:action=>"buyback"},:method => :post, :html=>{:class=>"form-horizontal"}) do |f| %>

Related

Turbo Stream link_to strips out custom attributes in GET request

I'm using Rails 7. I wanted to create a link using link_to that inserts some custom form fields for a many-to-many relation into a form via a hotwired frame elsewhere on the page. In order to customize the form fields generated (setting defaults etc) I need to include some custom parameters in the request:
<%= link_to "Add crew to ship",
new_crew_path(ship_id: ship.id),
data: { turbo_method: :get,
turbo_stream: true } %>
The HTML looks correct, but when clicking the link, the parameter seems to have been stripped away:
<a data-turbo-method="get" data-turbo-stream="true" href="/crews/new?ship_id=1">Add crew to ship</a>
...
Started GET "/crews/new" for 127.0.0.1 at 2023-01-24 13:49:23 +0100
Processing by CrewsController#new as TURBO_STREAM
If I remove the data map defining turbo_stream: true so it becomes a regular request, it works fine:
<%= link_to "Add crew to ship",
new_crew_path(ship_id: ship.id) %>
Started GET "/crews/new?ship_id=1" for 127.0.0.1 at 2023-01-24 13:53:26 +0100
Processing by CrewsController#new as HTML
Incoming parameters: {"ship_id"=>"1"}
Same for changing it to a POST request, so it goes to the #create action of the controller instead, that also works:
<%= link_to "Add crew to ship",
crews_path(ship_id: ship.id),
data: { turbo_method: :post,
turbo_stream: true } %>
Started POST "/crews?ship_id=1" for 127.0.0.1 at 2023-01-24 13:58:01 +0100
Processing by CrewsController#create as TURBO_STREAM
Incoming parameters: {"ship_id"=>"1"}
So I have workarounds. Nevertheless, out of curiousity, is there some way to make GET turbo requests submit the custom params? From a REST perspective it feels like the most correct request method.
When you add turbo_method: :get the link is treated as a form and GET forms overwrite url query params with form params. As a test:
// app/javascript/application.js
document.addEventListener("turbo:before-fetch-request", (event) => {
console.log(event.target)
})
// you get this "fake" form in the console, that Turbo submits instead of a link:
// <form data-turbo="true" action="http://localhost:3000/?ship_id=1" hidden="" method="get" data-turbo-stream=""></form>
If you just change the link to this:
<%= link_to "Add crew to ship",
new_crew_path(ship_id: ship.id),
data: { turbo_stream: true } %>
Now it's a regular GET turbo stream link, and query params should stay untouched.
For some extra details:
https://github.com/hotwired/turbo/pull/647
it's worth emphasizing that declaring [data-turbo-method="get"] on an
<a> element is redundant, and should be avoided
https://github.com/hotwired/turbo/pull/821

Nested form to route to proper controller action

The routes define
resources :interruptions do
collection do
post :pause
post :restart
end
end
However, within an intervento_controller show action, where #interruption = Interruption.new is declared, a form to create a related record
<%= form_for #interruption, url: pause_interruptions_path do |f| %>
<%= f.hidden_field :intervento_id, value: #intervento.id %>
<%= submit_tag "Pausa", name: 'pausa_intervento' %>
<% end %>
rails is routing to the intervento action, not the one stated in the form_for url declaration.
Started PATCH "/interventos/32" for ::1 at 2017-01-17 13:04:49 +0100
Processing by InterventosController#update as HTML
Parameters: {"utf8"=>"✓", [...] "interruption"=>{"intervento_id"=>"32"}, "pausa_intervento"=>"Pausa", "id"=>"32"}
The model Intervento does allow accepts_nested_attributes_for :interruptions, however I expected this not be necessary as the form declares the action to be routed to. Also, only one record is being created or edited at a time.
How can this be achieved?
Your pause action is defined on collection, i.e /interventos/post,
however, your form is defined for an interruption instance.
You think you meant to do
resources :interruptions do
member do
post :pause
# post :restart
end
end
and you also need to change pause_interruptions_path accordingly.
Also try use f.submit
submit_tag seems being treated as a input field.

No route matches [POST] "/" when posting a form

I'm trying to set up a form on my index page that will pass a param myform, to the same index page via a GET request. I thought this would be relatively simple. but I'm getting an error.
I generated a controller, RecipesController, with a method called index:
class RecipesController < ApplicationController
def index
#search = params[:myform]
return #search
end
end
In this method I'm trying to get back what the user types into a textbox when a button is pressed and the GET request is fired.
Here is my view:
<h1>Recipe Finder</h1>
<%= form_tag(controller:"recipes",method:"get") do %>
<%= label_tag(:myform, "Search") %>
<%= text_field_tag(:myform) %>
<%= submit_tag("search") %>
<% end %>
Here are my routes:
Rails.application.routes.draw do
root 'recipes#index'
This shows up fine when I visit localhost:3000, but when I press the button I'm expecting the controller index method to just return whatever text i typed into the textbox. Unfortunately, I only get:
No route matches [POST] "/"
I know setting the root to recipes#index is causing the failure as my #search variable is not set when the page is opened initially.
I'm wondering if I should have a separate route and method for the GET request and should I just open the main page with the call to localhost:3000 without running any code in the controller? Is this possible?
The problem is that form_tag accepts a Hash as both its first and second argument. If you don't use brackets, it's going to interpret all of it as part of the first argument, and your method: "get" is not applied properly.
Because of this, it defaults to doing a POST request, for which there is no route.
Try this. Because the first argument is no longer a Hash, it should work properly:
<%= form_tag("/", method: "get") do %>
Alternatively, using your code, you can try this:
<%= form_tag({ controller: "recipes" }, { method: "get" }) do %>

Rails: flash message shows in the url as param

Hi all my flash messages work in the normal fashion but there is an action in one of my controllers where the flash message does not work.
This is the view:
<%= form_tag update_status_order_path(update_status), method: :put do |f| %>
<%= select(:order, :status, [['Active', 1], ['Inactive', 0]]) %>
<%= submit_tag "Update" %>
<% end %>
This is the controller action
def update_status
if #order.update_order_status! params[:order][:status]
redirect_to show_orders_ofert_path #order.ofert, success: "Updated!."
else
redirect_to show_orders_ofert_path #order.ofert, error: "Error."
end
end
When I send the form the action is performed correctly, but the flash message is not displayed in the layout, instead is displayed in the url as a param, just after click the Update button it reloads and shows the url like this:
http://localhost:3000/oferts/48/show_orders?success=Updated!
I have tried changing put to patch but it did not worked, even changing the action to work with respons_to block but it did not work, any idea?
this problem is only happening with that specific action because with the other actions I have the flash messages are isplayed normally.
Thanks
The success and error keys are being used as parameters to the show_orders_ofert_path because there are no parenthesis. Add parenthesis around the path helper arguments:
redirect_to show_orders_ofert_path(#order.ofert), success: "Updated!."

routing scope problem with form_for (partial)

Trying to route:
scope :shortcut do
resources :text_elems
end
Using basic scaffold with form partial
*_form.html.erb*
<%= form_for(#text_elem, :shortcut => #shortcut) do |f| %>
...
Problem is: When I call the edit action, the form html shows as:
<form ... action="/25/text_elems/25">
Note: The new action renders the form action correctly:
<form ... action="/home/text_elems">
So it appears that my :shortcut param is getting trumped by the :id param when form_for processes it's block. Now I am able to get the action to correctly route with the :shortcut param if I manually make the :url => {...} in the form_for block, but I would prefer to keep the code dry, plus I want to report this problem to rails if it is indeed a bug.
Can anyone else confirm this as a bug?
Actually, you can pass the values as a full hash, rather than trying to rely on the default to_param (which is what gets called if all you do is pass the #text_elem)
<%= form_for({:id => #text_elem.to_param, :shortcut => #shortcut}) do |f| %>
however, if this is actually a nested-resource, you could also do:
<%= form_for([#shortcut, #text_elem]) do |f| %>
I was having the same issues and none of the above answers helped.
The last answer on this page worked for me though...
https://rails.lighthouseapp.com/projects/8994/tickets/6736-problem-with-scoped-routes-and-form_for-helper

Resources