I'm trying to submit a RoR Form. Strong Params are fine as I'm not getting a not permitted message in the logs. For some reason, I keep getting a this field cannot be blank error message for the below field. The logs say the client_name field is blank even though I've selected something. There's a has-many/belongs-to relationship between designer & client-folder.
When I choose one of the existing client_folder from the dropdown and press submit, it gives the error message. If I use a text field and simply type a name, it works fine, so I believe it's just something with collection_select. Where am I going wrong?
<%= form_for([#designer, #client_folder]) do |f| %>
<%= f.collection_select :client_name, current_designer.client_folders, :id, :client_name, {}, {id: "existing-list", required: true} %>
<%= f.submit "Create" %>
<% end %>
Related
I'm working on a rails project and I've come across something that seems strange. I have a form in my view, and for any normal field such as f.text_field if the model doesn't have the required attribute, I get an error, for example:
f.text_field :thing_that_doesnt_exist
gives me the error:
undefined method `thing_that_doesnt_exist' for #<Model:0x007f7d00b809a0>
However:
f.hidden_field :thing_that_doesnt_exist
doesn't give me an error and I'm not sure why, surely it should work the same way as the text field. If anyone can help me understand what's going on here I would greatly appreciate it.
Case1: Works without error
<%= f.hidden_field :thing_that_doesnt_exist, :value => "x" %>
<%= hidden_field_tag 'thing_that_doesnt_exist', "x" %>
Case2: Throws error if value not mentioned(as it will try to call attribute name which is not present)
<%= f.hidden_field :thing_that_doesnt_exist%>
<%= hidden_field_tag 'thing_that_doesnt_exist'%>
Case3: Works for existing field thing_that_does_exist
<%= f.hidden_field :thing_that_does_exist%>
<%= hidden_field_tag 'thing_that_does_exist'%>
Let us say that the user submits a form. One of the fields was invalid, so the form gets re-rendered. When in the process of re-rendering the form: I check to see if the submitted value for that attribute was invalid. If so: then show that invalid data entry with some additional text.
Here is what I have so far. It is close but isn't working completely:
<%= form_for(blog) do |f| %>
<div class="field">
<%= f.label :age %>
<% if f.object.age %>
<% if f.object.errors.include?(:age) %>
<%= f.text_field :age, value: "Submitted: #{f.object.age} was bad" %>
<% else %>
<%= f.text_field :age %>
<% end %>
<% else %>
<%= f.text_field :age %>
<% end %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
So I am saying: "Hey Rails: if the user has already submitted this form, and the value the user submitted for this attribute of age was invalid, then re-render the submitted value within the input, along with some additional text."
The issue I am having is that it will not show the error input correctly. For example: if the user inputs "abcd" into the input field, then when the form re-renders upon failing validations, the input field should say: "Submitted: abcd was bad". Instead it says "Submitted: 0 was bad".
I am close. The ultimate question is: Why is it displaying 0? Why isn't it displaying "abcd"? The next question is: "How can I make it display "abcd"?
Is this behavior because I have the following validation? :
validates :age, numericality: true
If so: how can I have the validation to ensure it is a number, but also re-display the value the user entered?
This is failing because you're calling f.object.age in an interpolated string, not the value submitted.
Since you're validating the numericality on age, your 'abcd' input will never pass validation and therefore would never saved.
So when you're calling .age on that object, you're only getting the default value, or the last value that passed validation and was saved. Your 'abcd' string would never have been saved.
An easier way to show the error would be to do:
f.object.errors.full_messages_for(:age)
You could also try adding a custom error message:
validates_numericality_of :age, message: '%{value} is not a valid age'
This works. Just grab the submitted value from the params hash:
<div class="field">
<%= f.label :age %>
<% if f.object.age %>
<% if f.object.errors.include?(:age) %>
<%= f.text_field :age, value: "Submitted #{params[:blog][:age]} is bad" %>
<% else %>
<%= f.text_field :age %>
<% end %>
<% else %>
<%= f.text_field :age %>
<% end %>
</div>
It appears that f.object.age does not work because the age attribute is of type integer. because of this: within the writer method for the age attribute:
def age=(value)
...
end
Somewhere within that setter what probably happens is that rails attempts to convert the submitted value with: to_i. When you do to_i on a string it returns 0, so when you attempt f.object.age it will return 0 because the writer attempted to convert the string.
The other tricky thing is the text_field method. Rails has some magic going on in there. For example: if there was nothing special going on: the following would successfully display the submitted value as opposed to 0:
<%= f.text_field :age %>
So somewhere within the text_field method, rails looks to see if that attribute of age was invalid, and if it was, then it specifies as the value the submitted value.
Without digging into the rails source code, it is tough to say how text_field figures out if the attribute was previously submitted, AND if the submitted value was invalid. Thus: if one dug within the rails source code I am sure you could clean up the conditionals up above once you figure out how text_field displays the submitted value (ex: 'abcd' as opposed to the converted value from the setter (ex: '0').
Nonetheless: the above code works and does what is desired.
I'm developing a simple rails app where I want to plot some stock charts. The problem is that when I start my server and load localhost the default value/ticker symbol is not loading which means that I have to type in a ticker in my form for it to work.
I found this thread where I learnt how to write a default value in my form/view, like so:
<%= form_for :find_it do |f| %>
Ticker symbol: <%= f.text_field :string, :value => "JPM" %></br>
<%= f.submit "Find" %>
<% end %>
and that's all fine, but it does not submit the value by default.
So how do I go about fixing this and what is the best practice?
In your input field you have list your attribute as a string, while that is the type, it most likely isn't the actual name of the attribute you wish to save "JPM". So you should change
<%= f.text_field :string, :value => "JPM" %>
to
<%= f.text_field :attribute_name, :value => "JPM" %>
If I copy and paste your form into a Rails app on my machine it does display a text field populated with "JPM", which I believe is correct.
When you hit submit the form will post to a create action with params containing:
"find_it"=>{
"string"=>"JPM"
}
Another thing I noticed is that you have f.text_field :string. This should be the name of your attribute, rather than the type (i'm assuming that you don't have a field called string).
I am useing a form_for helper to collect data on the client side of my application. However something weird is happening. I am not collecting the :name and :description and they are both returning as nil. this is my code:
<%= form_for #type do |f| %>
....
<%= f.text_field :name, :class => "col-xs-4" %>
<%= f.text_field :description, :class => "col-xs-4" %>
<%= f.submit %>
....
Do I need to make a fields_for under the form_for to get this working? It is a bit tricky because I am using #type which in this case is set up to tell the view which kind of attr. they are looking at. For example, this line:
<%= f.label #type %> <label> Description</label>
depending on what view you are on shows ether:
Group Description
or
Tag Description
and because they are both technically the same, I am using the same index for both. I hope I am clear with my issue and thank anyone who understands my problem and solution.
The param name will depend on the object you pass.
If #type contains an instance of Group, then you will get the params under params[:group], and if it is an instance of Tag, the you will get them on params[:tag]
<%= form_for #type do |f| %>
<%= f.label :name, "#{#type.model_name} Description" %>
<%= f.text_field :name %>
<%= f.submit %>
<% end %>
Note the label definition. The way you are defining it will create 2 labels and the second one will not be linked to any field.
fields_for is normally used when you are creating several objects within the same form, for instance a Project and several tasks associated to it.
Hope this helps.
update:
If #type is a string or symbol it should work too. The tradeoffs using this approach will be that if there are any validation errors when creating the object, those will not be displayed and the fields will not be prefilled with the input that the user gave before submitting the form, forcing the user to enter all the information again and guessing which was the validation error (you can initialize it from the received params, but that complicates the code readability)
The unique thing different in your view would be the label definition.
<%= f.label :name, "#{#type} Description" %>
I have a form that allows the user to search for existing records to populate an association. Each "Booking" belongs to a "Customer". So the form allows you type the customer's name, it does a search automatically, and you click the customer you want. The input field you're typing into should display the customer's name, but for the form to work, I set the customer_id in a hidden input field.
I'm using the simple_form gem. Does anybody know if I can display the validation errors for the customer_id next to the text input field that displays the customer's name? The customer_id is required in the model, so I need the form to tell the user that if they leave it blank.
View code (simplified -- there's some JavaScript that handles searching when you type into the customer text box, and that sets the value in the hidden field to the customer's id when you make a selection):
<%= simple_form_for #booking do |f| %>
<%= f.hidden_field :customer_id, id: "customer_id" %>
<%= f.input :customer, required: true,
input_html: { value: #booking.customer_name } %>
<% end %>
I eventually found out about the append block in simple_form (buried in a pull request, not documented anywhere else that I could find). Basically, you can use that to append whatever markup you want to your f.input. I did the following, which is pretty hacky, but it does what I need it to do:
<%= f.input :customer, required: true,
wrapper_html: { class: ("error" if #booking.errors[:customer_id].any?) } do %>
<%= f.input_field :customer, value: #booking.customer_name %>
<%= f.error :customer_id %>
<% end %>
First, I had to conditionally add the class "error" to the wrapper if there were any errors on the related field, then I used the append block to render out the input field, followed by the errors for the related field from the model. Hope this helps someone in the future!