routing scope problem with form_for (partial) - ruby-on-rails

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

Related

Rails form_with defaulting to incorrect method

I'm using Rails 6. I have a route that defines a get request:
namespace :admin do
get '/machines/search', to: 'machines#search', as: 'search_machines'
end
Then, I have a form_with that sets the url to the route. When the form is loaded, the HTML that's generated for the form contains a method="post" instead of method="get" which is what I would've expected since the route is a GET request and not a POST. I can add the method: "get" parameter to the form_with and this fixes the issue but I don't understand why Rails didn't pick up the correct method initially.
<%= form_with url: admin_search_machines_path() do |i| %>
<%= i.text_field :q, placeholder: "Search", autocomplete: "off", class: "debounce-form-submit form-control" %>
<% end %>
According to the documentation form_with does default to POST if method is not specified. Which is not 100% correct, as it will switch to PATCH (via hidden field trick) if the model is persisted (source).
Up to today, the code does not look at the route itself to specify the method.
I think the (backwards incompatible) automagic you suggest is not totally off, though. You might ask about that in the rubyonrails forums and get feedback whether this would be a welcomed change. Personally, I never expected it to inspect the route. Also, you might have the same route with post and get methods, which would make lookup more involved than what meets the eye on first sight.

wrong number of arguments (3 for 2) in form_for method

I'm upgraded to rails 3.2.13 and I'm migrating an old app to run in the new environment (ruby1.9.3). The app ran fine with ruby192 and rails 3.0.0.
I was receiving this error when trying to create a new record (a firefighter)
wrong number of arguments (3 for 2)
And here was my code for my form
<%= form_for :fire_fighter, #fire_fighter, :url => { :action => "create" } do |f| %>
based on reading other posts, they recommend to remove "fire_fighter" but so it would look like this
<%= form_for :#fire_fighter, :url => { :action => "create" } do |f| %>
This did actually allow the page to render but when I tried to enter fill in the text fields and submit or create the record in the database I get an error message that is built into the app that says:
All of the fields are setup as strings.
Oh and obviously i had all this fields filled out before I hit submit. So now I'm just stuck.
Any help would be appreciated thanks.
Although this answer may change when you post your page source code and the rest of the form code, you are trying to create a symbol from an instance variable.
<%= form_for :#fire_fighter, :url => { :action => "create" } do |f| %>
Notice :#fire_fighter. It really should be #fire_fighter. The correct code should then be
<%= form_for #fire_fighter, :url => { :action => "create" } do |f| %>
The reason why you use an instance variable like #fire_fighter is because in your controller there should be something like
def new
#fire_fighter = FireFighter.new
end
that way, the form is directly grabbing the instance variable from the controller onto the form. Symbols don't transverse from controllers to views, but instance variables do, hence the use of #fire_fighter as the first argument in the form_for method.

rails 3 nested resource form for works in New but not in Edit

I have a pretty straight forward nested form.
Categories has_many awards has_many recommendations.
So my recommendation form is a partial and the form_for leads off with:
<%= form_for [#category, #award, #recommendation], :url => category_award_recommendations_path(#category, #award, #recommendation), :html => { :multipart => true} do |f| %>
this works fine and processes for the #new form. But when I mess with the #edit view it renders fine but when I submit it it uses the following url:
http://localhost:3000/categories/1/awards/1/recommendations.112
Question:
Why does it render the "." instead of a "/"
You are using category_award_recommendations_path, when it should be category_award_recommendation_path (notice the s missing at the end of recommendation).
EDIT: This is the answer for
Why does it render the "." instead of a "/"
Your form action url should change wether it's creating something or editing something. form_for does it itself when you don't supply the :url option, based on wether the object is persisted or not.

How can you pass an object from the form_for helper to a method?

So let's say I have a form which is being sent somewhere strange (and by strange we mean, NOT the default route:
<% form_for #form_object, :url => {:controller => 'application',
:action => 'form_action_thing'} do |f| %>
<%= f.text_field :email %>
<%= submit_tag 'Login' %>
<% end %>
Now let's say that we have the method that accepts it.
def form_action_thing
User.find(????? :email ?????)
end
My questions are thus:
How can I make the object #form_object available to the receiving method (in this case, form_action_tag)?
I've tried params[:form_object], and I've scoured this site and the API, which I have to post below because SO doesn't believe I'm not a spammer (I'm a new member), as well as Googled as many permutations of this idea as I could think of. Nothing. Sorry if I missed something, i'm really trying.
How do I address the object, once I've made it accessible to the method? Not params[:form_object], I'm guessing.
EDIT
Thanks so much for the responses, guys! I really appreciate it. I learned my lesson, which is that you shouldn't deep-copy an object from a form, and that the parameters of a form are actually included when you submit it.
I will admit it's sort of disheartening to not know stuff that seems so obvious though...
you need to pass the "id" of your "#form_object" in the url and then lookup that object (assuming you have a model and using ActiveRecord)
It depends on how do you set up your routes. If you're using the default /:controller/:action/:id route, you can pass it as a parameter in the URL. Note that not the whole #form_object can/should be passed, but it's id or some other attribute to identify it instead. In this case, you should make your URL:
<% form_for #form_object, :url => {:controller => 'application',
:action => 'form_action_thing', :email => some_email} do |f| %>
<%= f.text_field :email %>
<%= submit_tag 'Login' %>
<% end %>
And in your controller
def form_action_thing
#user = User.find_by_email(params[:email])
end
You can pass parameters through the url, but when submitting a form the only thing that should (probably) be passed through the url is the record id for a RESTful record.
And it appears you didn't find out yet where your form data can be found in the params.
So
All the data from your form should end up in params[:form_object]. The actual value for :form_object is selected by Rails, it's probably coming from the object's class (too lazy to look that up right now)
In any case, you can easily find out where your form values are submitted by looking at your console/log output. All the params for each requests are dumped there.
The form fields will be inside the params like params[:form_object][:email] - each field that is submitted has an entry corresponding to the field name.
The params hash not contain all the original values from your #form_object. There will be only those values that you included in the form.
If you need to pass non-editable values to the controller with your form, use hidden_field(s) These will be submitted with the form, but are not visible to the user.

Rails: form.error_messages does not wrap custom validated fields in a fieldWithErrors div

I have a model that uses the low level validate_on_create method, based on a simple condition I'm adding an error message to the field, e.g
self.errors.add(:expiry_date, "is too soon") if self.expiry_date && self.expiry_date < Date.today + 1.week
When rendering the view 'new' after a failed save the field isn't picked up by error_messages_for as I would expect. The error is shown in the ususal list of errors that indicated the validation is working correctly.
Has anybody got any idea why this is? I guess form.error_messages isn't looking at all errors on the object?
Added the requested code:
<% form_for([:solicitor, #policy]) do |form| %>
<%= form.error_messages :message => "See the list of reasons below to find out why not:", :header_message => "Sorry but we cannot yet create your policy based on the information you've provided." %>
<%= render :partial => 'form', :locals => {:form => form} %>
<% end %>
More than likely your problem is:
You are not passing the form_for the correct options.
You are redirecting back to the form instead of rendering.
You aren't using the form_for builders (ie text_field_tag instead of f.text_field)
However, without posting your full controller/view, I'm basically just guessing.
The problem was a simple typo in the form partial. I should have posted all the code in question as I'm sure if I did BJ Clark or others would have easily spotted the silly mistake I made
Lesson learned!

Resources