Rails form formatting - ruby-on-rails

I've just had Submitting multiple forms in Rails answered which led to another problem. In my form I have the following (there's quite a bit more):
= hidden_field_tag :event_id, :value => #event.id
.control-group
= label_tag :title
.controls
= select(:registration, "registrations[][title]", Registration::TITLE)
and the last line returns:
"registrations"=>[{"title"=>{"registration"=>"Mr"},
as opposed to the expected:
"title"=>"Mr"
I've tried:
= select(:registration, "registrations[][title]", Registration::TITLE)
which returns:
undefined method `registrations[][title]' for #
and also tried:
= select("registrations[][title]", Registration::TITLE)
which returns:
wrong number of arguments (2 for 3)
Look at the parameters below, event(_id) is only there once then the :title oddness starts, any idea what the problem may be?
{"utf8"=>"✓",
"authenticity_token"=>"BQXm5fngW27z/3Wxy9qEzu6D8/g9YQIfBL+mFKVplgE=",
"event_id"=>"7",
"registrations"=>[{"title"=>{"registration"=>"Mr"},
"first_name"=>"Name1",
"last_name"=>"Surname1",
"company_name"=>"Company1",
"designation"=>"Designation1",
"landline"=>"Landline1",
"cell"=>"Cell1",
"email"=>"address1#example.com",
"member"=>{"registration"=>"No"},
"dietary"=>{"registration"=>"None"},
"specify"=>"None"},
{"first_name"=>"Name2",
"last_name"=>"Surname2",
"company_name"=>"Company2",
"designation"=>"Designation2",
"landline"=>"Landline2",
"cell"=>"Cell2",
"email"=>"address2#example.com",
"member"=>{"registration"=>"No"},
"dietary"=>{"registration"=>"None"},
"specify"=>"None",
"title"=>{"registration"=>"Mr"}},
{"first_name"=>"Name3",
"last_name"=>"Surname3",
"company_name"=>"Company3",
"designation"=>"Designation3",
"landline"=>"Landline3",
"cell"=>"Cell3",
"email"=>"address3#example.com",
"member"=>{"registration"=>"No"},
"dietary"=>{"registration"=>"None"},
"specify"=>"None"}],
"commit"=>"Submit registrations"}
Please not that :dietary and :member are formated in the same way as :title. Thanks in advance for your assistance!
EDIT
So submitting to the hash via a text_field_tag is a simple is:
= text_field_tag "registrations[][first_name]"
But the problem comes in with my hidden_field_tag and select_tag.
It's adding bad values, for example:
"title"=>{"registrations"=>"Mr"}
and basically it seems I need to find a better way to add those values into the hash. I'll continue trying to find a solution and will post it here unless someone beats me to it.

Unless i'm reading it wrong, your first two select calls are the same. Have you tried = select(:registrations, "title", Registration::TITLE)? If you look at the documentation of the method in api.rubyonrails.org, it will state that the first value is the object, second is the property. That would be registrations => { :title => "Value" }, in the parameters. If you just want :title => "Value", then you need the select_tag method.

Related

Ruby on Rails: putting class with submit_tag

I was wondering why we have to add a nil when putting :class => "class_name"
<%= submit_tag nil, :class => "class_name" %>
but for this:
<%= f.submit class: "class-Name" %>
I don't need to add the nil
Thanks
<%= submit_tag("Update", :id=>"button", :class=>"Test", :name=>"submit") %>
First parameter is required and it would be value and they any parameter you want to specify, can be done in a hash like :key=>"value".
A look to the way that submit_tag method was implemented clearly answers your question.
def submit_tag(value = "Save changes", options = {})
options = options.stringify_keys
if disable_with = options.delete("disable_with")
options["data-disable-with"] = disable_with
end
if confirm = options.delete("confirm")
options["data-confirm"] = confirm
end
tag :input, { "type" => "submit", "name" => "commit", "value" => value }.update(options)
end
It takes two arguments, the first is value which by default is "Save changes" and the second is a Hash of options. If you don't pass nil then it will assume that that's the value you want for the input.
Because they are two different methods...
The "submit" method doesn't take a caption because it can infer one from the form that the method is called on, and what object was used to build the form.
The "submit_tag" method is not called on a form object. It is used for more customized form building (more separated from your activerecord model, for example) and so the code can't infer a caption and must get a value as the first argument. All the "formelement_tag" methods (documented here, for example) are like this and can infer less based on your data model.
Obvious answer is that submit_tag and submit are simply different form helper methods that takes different arguments.
The _tag series of methods usually require a name parameter (otherwise they'd be fairly useless tags, so it's always the first argument instead of part of the hash. Because the submit helper is called as part of the form, Rails can assume the field's name property and can then make the options hash the first argument.

Array as Parameter from Rails Select Helper

I'm working on a legacy project that is using acts_as_taggable_on which expects tags to come in arrays. I have a select box allowing users to select a tag on a Course in a field called categories. The only way mass assignment create will work is if params looks like this params = {:course => {:categories => ['Presentation']}}. I've currently a view with this helper:
<%= f.select 'categories', ['Presentation' , 'Round Table' , 'Demo', 'Hands-on'] %>
Which will give me a parameter like params = {:course => {:categories => 'Presentation'}}. This doesn't work since Acts as tag gable apparently can't handle being passed anything other than a collection.
I've tried changing categories to categories[] but then I get this error:
undefined method `categories[]' for #<Course:0x007f9d95c5b810>
Does anyone know the correct way to format my select tag to return an array to the controller? I'm using Rails 3.2.3
I didn't work with acts_as_taggable_on, but maybe this simple hack will be suitable for you? You should put it before mass-assignment.
category = params[:course][:categories]
params[:course][:categories] = [category]
If you are only going to allow the selection of ONE tag, you could do:
<%= f.select 'categories', [['Presentation'] , ['Round Table'] , ['Demo'], ['Hands-on']] %>
Each one item array will have first for the display value, and last for the return value, which in this case will both return the same thing, as the first element of the array is the same as the last element when the array as one element.
Seems like select doesn't give you that option.
If I understand correctly, one option might be to use a select_tag instead and just be explicit about where you want the selection in the params:
<%= select_tag 'course[categories][]', options_for_select(['Presentation' , 'Round Table' , 'Demo', 'Hands-on']) %>
That ought to get your params the way you need them.
Here's what I'm using for one of my projects:
<% options = { include_blank: true } %>
<% html_options = { required: true, name: "#{f.object_name}[#{resource.id}][days][]" } %>
<%= f.select :days, DAYS, options, html_options %>
Without html_options[:name], Rails handles the name of the select tag and spits out something like
service[service_add_ons_attributes][11][days]
but I need
service[service_add_ons_attributes][11][days][]
So I override it.
Hope that helps.

How to display Rails select field values rather than stored integers in other views

I'm using a select field in a Rails app that is NOT tied to a related model, but stores integer values for a static series of options , i.e.,
<%= select (:this_model, :this_field, [['Option1',1],['Option2',2],['Option3',3],['Option4',4]] ) %>
In a show/ index view, if I want to display the option text (i.e. Option1, Option2, etc) rather than the integer value stored in the database, how do I achieve this?
Thanks for helping a noob learn the ropes!
EDIT
Based on Thorsten's suggestion below, I implemented the following. But it is returning nil, and I can't figure out why.
Invoice model:
##payment_status_data = { 1 => "Pending Invoice" , 2 => "Invoiced" , 3 => "Deposit Received", 4 => "Paid in Full"}
def text_for_payment_status
##payment_status_data[payment_status]
end
Invoice show view:
Payment Status: <%= #invoice.text_for_payment_status %>
In the console:
irb > i=Invoice.find(4)
=> [#<Invoice id: 4, payment_status: 1 >]
irb > i.text_for_payment_status
=> nil
I've tried defining the hash with and without quotes around the keys. What am I missing?
something like this would work:
<%= form_for #my_model_object do |form| %>
<%= form.label :column_name "Some Description" %>
<%= form.select :field_that_stores_id, options_for_select({"text1" => "key1", "text 2" => "key2"}) %>
<% end %>
Update
If you later want to display the text you can get it from a simple hash like this:
{"key1" => "text 1", "key2" => "text2"}[#my_object.field_that_stores_id]
But you better store this hash somewhere in a central place like the model.
class MyModel < ActiveRecord
##my_select_something_data = {"key1" => "text 1", "key2" => "text2"}
def text_for_something_selectable
##my_select_something_data[field_that_stores_id]
end
end
Then you can use it in your views like
#my_object.text_for_something_selectable
There are many possible variations of this. But this should work and you would have all information in a central place.
Update
Ok, I used something similar for our website. We need to store return_headers for rma. Those need to store a return reason as a code. Those codes are defined in an external MS SQL Server Database (with which the website exchanges lots of data, like orders, products, and much more). In the external db table are much more return reasons stored than I actually need, so I just took out a few of them. Still must make sure, the codes are correct.
So here goes he model:
class ReturnHeader < AciveRecord::Base
##return_reason_keys = {"010" => "Wrong Produc",
"DAM" => "Damaged",
"AMT" => "Wrong Amount"}
def self.return_reason_select
##return_reason_keys.invert
end
def return_reason
##return_reason_keys[nav_return_reason_code]
end
end
Model contains more code of course, but that's the part that matters. Relevant here is, that keys in the hash are strings, not symbols.
In the views i use it like this:
In the form for edit:
<%= form_for #return_header do |form| %>
<%= form.label :nav_return_reason_code "Return Reason" %>
<%= form.select :nav_return_reason_code, options_for_select(ReturnHeader.return_reason_select, #return_header.nav_return_reason_code) %>
<% end %>
(Maybe no the most elegant way to do it, but works. Don't know, why options_for_select expects a hash to be "text" => "key", but that's the reason, why above class level method returns the hash inverted.)
In my index action the return reason is listed in one of the columns. There I can get the value simply by
#return_headers.each do |rh|
rh.return_reason
end
If you have trouble to get it run, check that keys a correct type and value. Maybe add some debug info with logger.info in the methods to see what actual data is used there.

Formtastic non-model form, integration with external site, override/specify the input ID values

I'm using formtastic to collect information from a form and post dirctly to an external site.
I have no problem generating the form itself. However, since this is being submitted to an external site, they require that each input field have the specific IDs they specify, eg email or last_name -- not the closest Formtastic form, eg _email_input or _last_name_input.
I've looked at the Formtastic v1.2.3 code and I'm 90% sure the answer is "sorry, can't do that." I figured it couldn't hurt to check if I'm missing something. I would like some way to specify the ID completely, as in:
= semantic_form_for('', :url => "https://external_site.com/handler, :method => "post") do |form|
= form.input :last_name, :id => "last_name"
[etc]
Is this possible?
(I will note that I recognize that another, arguably superior approach would be to create an appropriate controller, sanity check the parameters locally, and dispatch the remote call from within the app only when it's well formed; however, that's not what I'm trying to do at the moment.)
Firstly i think you need to use semantic_fields_for for non-model forms. Next, to pass ids to each field, you can use the input_html options to specify them. for eg
form.input :email, :input_html => {:name => 'email', :id => 'email' }

Generating unique HTML ids in Rails when using a repeated partial that has form_for

I have a view on my current project which does something like the following(in haml):
-#horses.each do |horse|
= render :partial => 'main/votingbox', :locals => {:horse => horse}
The in the _votingbox.html.haml file I have the following:
%div.votingbox
%span.name= horse.name
%div.genders
- if horse.male
%img{:src => 'images/male.png', :alt => 'Male'}
- if horse.female
%img{:src => 'images/female.png', :alt => 'Female'}
%div.voting_form
= form_for(Vote.new, {:url => horse_vote_path(horse)}) do |f|
= f.label :comment, "Your opinion"
= f.text_field :comment
...
a bunch of labels and input elements follow generated using the form helpers
This will generate working code but it does generate forms with the same ids for all the form elements which makes the HTML invalid once the votingbox partial is rendered a second time.
My first guess at fixing this was to specify a unique :id to form_for but that only applies to the form tag generated by form_for and not any of the tags inside the form_for block.
One definite solution to this problem is to go through and manually define my own unique ids on form_for and all the form elements I use. This is more work than I had hoped for.
Is there an easier or cleaner way to get unique ids in a similar format to the way Rails currently generates them on all my form elements?
I have removed the original answer as it is totally irrelevant to the updated version of the question.
Update: So now we know that you have an unsaved ActiveRecord object passed to the form_for call, the answer becomes simple: You can override any parameter that form_for generates. That includes the element id. And fields_for sets the context for a specific record.
= form_for(Vote.new, :url => horse_vote_path(horse), :id => dom_id(horse, 'vote')) do |f|
= f.fields_for horse, :index => horse do |fh|
= fh.text_field :whatever
…
You can override the autogenerated ids and names of all form_for content with :as like the following:
= form_for(Vote.new, :as => horse.name, {:url => horse_vote_path(horse)}) do |f|
= f.label :comment, "Your opinion"
= f.text_field :comment
So if a given horse.name is foobar, it will generate a comment field whose id is foobar_comment and name is foobar[comment]
But remember to make sure that the dynamic parameter is acceptable as an html id, a horse.name like hor$e is not acceptable as an html id and therefore might break something.
P.S: Sorry for answering very late, but at the time the question was asked, I haven't had learnt anything at all about rails! hope that might help someone out there!

Resources