Ruby on Rails: putting class with submit_tag - ruby-on-rails

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.

Related

Rails Action View Form Helper pass options hash to create element

Given a hash of properties for a text_field to be made in HAML:
entry = {class: "form-control", disabled: true, id: :foobar}
How can I do this:
%dd!= f.send(:text_field, entry[:id], class: entry[:class], disabled: entry[:disabled])
But flexible? (So don't need placeholders, just a hash). Have looked at simple form docs and action view form helper docs and found input_html, but that's not working in this manner.
The f.send is obligatory, as :text_field can be anything. Would prefer not to use eval
text_field takes:
text_field(attribute_name, input_html_options)
Does
f.text_field(entry[:id], entry)
not work?

How do I properly use a select box with ruby on rails?

I have a select box for the event types of an event. event belongs to event_type and event_type has many events. Here's what I have for the select box:
<%= f.select :event_type, options_from_collection_for_select(EventType.all, :id, :name, #event.id), :placeholder => 'Select an event type' %>
But, the problem is that when I submit it, it submits the id of the event type and not the name of it. So, how would I make it submit the name rather than the id? If you need to see the any more code than just tell me, thanks
The second parameter to options_from_collection_for_select is the value that will be submitted with the form. You have :id, so change it to :name.
http://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/options_from_collection_for_select
(but this seems like a strange thing to do - typically you would store the event type ID.)
You can use the id after the submit to load the event type again in your controller post action like this:
selected_type = EventType.find(params[:event_type]
It is also a good practice to keep database calls to the controller, so please put the EventType.all statement in there and pass it as local or class variable like you did with event.
If you really want to pass the name in your form instead of the id, you can replace the :id part in your call to something more like this options_from_collection_for_select(#event_types, :name, :name, #event.event_type.name). Keep in mind that this value should be unique!
The method works like this:
options_from_collection_for_select(collection, value_method, text_method, selected = nil)
So the first parameter contains all the options, the second defines the value within those option objects which are put into the value field of the HTML option (which is being submitted by the form), the third defines the text which is displayed to the user and the final parameter defines the value of the selected entry (in case you are editing an entry for example). For the last parameter, you need to use the events' event_type id, or in your case, the name because you set the value of your HTML tag to it.
Use pages like ApiDock or the Rails tutorials to get examples for some of these methods.
http://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/options_from_collection_for_select
You should pass name in the Value method, if you want to pass the name,
<%= f.select :event_type, options_from_collection_for_select(EventType.all, :name, :name, #event.id), :placeholder => 'Select an event type' %>
Here is the doc for options_from_collection_for_select

Rails form formatting

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.

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.

Can someone explain collection_select to me in clear, simple terms?

I am going through the Rails API docs for collection_select and they are god-awful.
The heading is this:
collection_select(object, method, collection, value_method, text_method, options = {}, html_options = {})
And this is the only sample code they give:
collection_select(:post, :author_id, Author.all, :id, :name_with_initial, :prompt => true)
Can someone explain, using a simple association (say a User has_many Plans, and a Plan belongs to a User), what I want to use in the syntax and why?
Edit 1: Also, it would be awesome if you explained how it works inside a form_helper or a regular form. Imagine you are explaining this to a web developer that understands web development, but is 'relatively new' to Rails. How would you explain it?
collection_select(
:post, # field namespace
:author_id, # field name
# result of these two params will be: <select name="post[author_id]">...
# then you should specify some collection or array of rows.
# It can be Author.where(..).order(..) or something like that.
# In your example it is:
Author.all,
# then you should specify methods for generating options
:id, # this is name of method that will be called for every row, result will be set as key
:name_with_initial, # this is name of method that will be called for every row, result will be set as value
# as a result, every option will be generated by the following rule:
# <option value=#{author.id}>#{author.name_with_initial}</option>
# 'author' is an element in the collection or array
:prompt => true # then you can specify some params. You can find them in the docs.
)
Or your example can be represented as the following code:
<select name="post[author_id]">
<% Author.all.each do |author| %>
<option value="<%= author.id %>"><%= author.name_with_initial %></option>
<% end %>
</select>
This isn't documented in the FormBuilder, but in the FormOptionsHelper
I've spent quite some time on the permutations of the select tags myself.
collection_select builds a select tag from a collection of objects. Keeping this in mind,
object : Name of the object. This is used to generate the name of the tag, and is used to generate the selected value. This can be an actual object, or a symbol - in the latter case, the instance variable of that name is looked for in the binding of the ActionController (that is, :post looks for an instance var called #post in your controller.)
method : Name of the method. This is used to generate the name of the tag.. In other words, the attribute of the object you are trying to get from the select
collection : The collection of objects
value_method : For each object in the collection, this method is used for value
text_method : For each object in the collection, this method is used for display text
Optional Parameters:
options : Options that you can pass. These are documented here, under the heading Options.
html_options : Whatever is passed here, is simply added to the generated html tag. If you want to supply a class, id, or any other attribute, it goes here.
Your association could be written as:
collection_select(:user, :plan_ids, Plan.all, :id, :name, {:prompt => true, :multiple=>true })
With regards to using form_for, again in very simple terms, for all tags that come within the form_for, eg. f.text_field, you dont need to supply the first (object) parameter. This is taken from the form_for syntax.

Resources