Using the textarea helper in Rails forms - ruby-on-rails

Why does this code show an error in text area?
<%= form_for(:ad, :url => {:action => 'create'}) do |f| %>
<%= f.text_field(:name) %>
<%= f.text_area_tag(:text, "", :size => "50x10") %>
<%= submit_tag("Submit") %>
<% end %>

The FormHelper method is text_area, not text_area_tag.
Use either of the following:
<%= f.text_area(:text, size: '50x10') %>
or:
<%= text_area_tag(:ad, :text, size: '50x10') %>

The f variable that you are creating in the first line is a reference to your FormBuilder. By default it references ActionView::Helpers::FormBuilder or you can create your own.
The FormBuilder helper for textareas is called text_area. FormBuilder helpers are smarter than regular HTML helpers. Rails models can be nested logically, and your forms can be written to reflect this; one of the primary things FormBuilder helpers do is keep track of how each particular field relates to your data model.
When you call f.text_area, since f is associated with a form named :ad and the field is named :text it will generate a field named ad[text]. This is a parameter convention that will be automatically parsed into a Hash on the server: { :ad => { :text => "value" } } instead of a flat list of parameters. This is a huge convenience because if you have a Model named Ad, you can simply call Ad.create(params[:ad]) and all the fields will be filled in correctly.
text_area_tag is the generic helper that isn't connected to a form automatically. You can still make it do the same things as FormBuilder#text_area, but you have to do it manually. This can be useful in situations that a FormBuilder helper isn't intended to cover.

Related

Rails: Form helper for enum attribute

I set category's viewable attribute as an enum
class Category < ActiveRecord::Base
enum viewable: [:only_self, :friends, :anyone]
end
How should I make them accesible in _form when users edit this attribute? Something like?
<%= form_for(#category) do |f| %>
<%= f.select(:viewable) %>
<% end %>
UPDATE------
<%= f.select(:viewable, options_for_select([["description1", "only_self"], ["description2", "friends"], ["description3", "anyone"]])) %>
The description for each is quite repetative, because I need to put them whenever I need to display, not just in the forms. Where should I put them?
In form_for, the f.select does not display the current value of the this field. It always is the first description1.
When using the plural form, rails provides the full key/value array, so you can call Category.viewables for the array, and with the help of options_for_select you'll get a nice functioning dropdown list
<%= form_for(#category) do |f| %>
<%= f.select(:viewable, options_for_select(Category.viewables)) %>
<% end %>
Updated answers
The description for each is quite repetative, because I need to put
them whenever I need to display, not just in the forms. Where should I
put them?
You can use the I18n library, assuming your locale is chinese (zh i think) then you could create /config/locales/zh.yml and add something like this
categories:
viewable:
only_self: 'some chinese text'
friend: 'more chinese text'
anyone: 'well you know'
Then better create some helper that returns the localized options
def options_for_viewables
{
t('categories.viewable.only_self') => 0,
t('categories.viewable.friends') => 1,
t('categories.viewable.anyone') => 2
}
end
The view will become like this
<%= f.select(:viewable, options_for_viewables) %>

Rails - how to render two identical forms but with different element IDs?

I would like to have two almost identical forms on a single page and use a partial for generating both with a render call.
<%= render 'form_template', data: #categories_one %>
<%= render 'form_template', data: #categories_two %>
The problem lies in their only difference - both forms use f.collection_select to provide dropboxes with categories for the user.
<%= f.collection_select :category_id, data, :id, :name %>
which creates two different forms with identical IDs for the SELECT tag, breaking my forms, and I would like to avoid that. But how can I do that?
You can pass :namespace parameter to the form_for
A namespace for your form to ensure uniqueness of id attributes on form elements. The namespace attribute will be prefixed with underscore on the generated HTML id.
If you look at the documentation for collection_select, you'll see that its last argument is for HTML options. So you can do this:
<%= f.collection_select :category_id, data, :id, :name, {}, {:id => "different_css_id"} %>
Since you said this is called within a partial though, from your identical render calls, you can pass along a variable to toggle this behaviour.
# Render calls
<%= render 'form_template', data: #categories_one %>
<%= render 'form_template', data: #categories_one, :locals => {:use_other_id => true} %>
And then use that flag in your partial.

Rails: Nested form with STI inheritance informing forms, how to make work with AJAX?

Okay, first and foremost, I am doing something very complicated. It's possible I've gone in a wrong direction.
What I currently have is a STI inheritance model, StateDescription. Subclasses of StateDescription describe a specific state I could care about, such as "LocationHasItem" or "ItemNearOtherItem" or what not.
I understand that I may eventually want to upgrade this to a multi-table inheritance model, as not all subclasses of StateDescription use all possible variables (though there is a high degree of overlap).
These StateDescriptions are owned by another class in a "has_many/belongs_to" relationship.
So, inside the form for this other class, I have:
<%= f.fields_for :conditions do |e| %>
<br>
<%= render :partial =>"/state_descriptions/form", :locals => {:e => e, :universe => #story_section.universe, :div_id => "condition"}%>
<Br>
<% end %>
The StateDescription itself checks for which type it should render, then renders the appropriate partial like so (only showing one subclass, for clarity's sake):
<div id="<%=div_id%><%=e.object.id%>">
<li>
<%= e.select(:type, StateDescription.subclasses.collect{|x| x.to_s}) %>
<br>
<%= e.label "Inverted?" %>
<%= e.check_box :invert %>
<Br>
<% if e.object.type.to_s == "StateDescription::ItNear" %>
<%= render :partial =>"/state_description/it_nears/form", :locals => {:e => e, :universe => universe, :div_id => div_id}%>
<% end %>
<% end %>
</li>
</div>
The subclass partial looks like:
<%=e.collection_select 'item_id', universe.items, :id, :title%>
<%= e.object.title_middle_fragment%>
<%=e.collection_select 'item2_id',universe.items, :id, :title%>
Thus the form starts out the same for all subclasses, and only differs as required.
This works PERFECTLY and I was very happy with it...until I decided I wanted to have ajax update the webpage with the correct form when the sublclass is chosen out of select input field.
Then I realized I couldn't pass the form helper reference ("e" in this case) to the partial from a controller.
IS there a best practice for this case, or I am just doing something so complicated I should do straight jQuery or something and leave rails out of it?
If I put the entire form (including the things each subclass has in common) in each subclasses form, that doesn't seem very dry. Not only that, I'm not sure that I would be able to then associate the StateDescription subclass back up to the parent class...
But, if I do it AJAX, I suppose I could not worry about nested forms and just have the parent be a hidden field or something, and have the StateDescriptions save on their own through AJAX?
Would this be the best solution (if it even works?) or is there some simple Rails way that I am missing?
Well, I still don't know if this is the easiest, or DRYist way to do it, but I ended up putting the whole form in the partial, and then just not bothering with nested forms. This worked just fine with the AJAX solution.
It makes me sad to repeat the form elements they have in common every time, but it's worth it for the AJAX functionality.
I'll try making a bit more DRY, it occurs to me I could try making the subclass partial not need a form, but it could still call a super class form partial to insert the elements each subclass has in common.
I had a similar problem with STI model, which is owned by another class in a "has_many/belongs_to" relationship. In order to build the form for this other class dynamically, I used cocoon gem, together with simple_form.
Cocoon adds methods that dynamically add/remove fields for each concrete class, that inherits from your base STI class.
For example (Publication is the owner class, Item is the base STI model, and Post, Video and Image inherit from it):
# _form.html.haml
= simple_form_for #publication, :html => { :multipart => true } do |f|
= f.simple_fields_for :items do |item|
= render 'item_fields', :f => item
= link_to_add_association 'Add a Post', f, :items, :wrap_object => Proc.new { |item| item = Item.new }
= link_to_add_association 'Add an Image', f, :items, :wrap_object => Proc.new { |item| item = Image.new }
= link_to_add_association 'Add a Video', f, :items, :wrap_object => Proc.new { |item| item = Video.new }
= f.button :submit, :disable_with => 'Please wait ...', :class => "btn btn-primary", :value => 'Save'
The :wrap_object proc passes the concrete class to item_fields which renders the correct partials, such as image_fields or video_fields or whatever.
I hope this helps.
I wrote a longer explanation for this problem at: http://www.powpark.com/blog/programming/2014/05/07/rails_nested_forms_for_single_table_inheritance_associations

Using Rails' form helpers without a model

For various reasons I need to avoid traditional nested forms (nested in the sense of treating the fields like a sub-group of the primary model for the page), but still want to keep fields grouped together with an index-style naming, so I have this:
<%= simple_fields_for :crate_request do |ff| %>
<%= ff.input :_create, :label => "crate needed", :as => :boolean %>
<%= ff.input :details, :as => :text %>
<% end %>
The rendered fields are named as expected (with names like params[:crate_request][:details]) and all looks well until I submit a form with validation errors and it has to come back to re-render. The fields don't prefill with the submitted values stored in the params hash. Although I'm using simple_form, it doesn't seem to just be a simple_form issue. The native Rails helpers appear to do the same.
So the question: is there any way to have the fields automatically pre filled from the params hash again without having to manually set the value of each field from params?
You would just need to pass some object as an extra argument to simple_fields_for.
As the form builder expects the object to have field accessors as methods, but you've only got a hash (params[:create_request]), you can use OpenStruct to create an object which would translate missing method calls to hash lookup.
The final solution then would look something like this:
<%= simple_fields_for :create_request, OpenStruct.new(params[:create_request]) do |ff| %>
...
<% end %>
Replace
<%= ff.input :details, :as => :text %>
by
<%= input :details, :as => :text %>

Best way to reload parts of a form

I want to reload a part of a form generated with the form_for-helper via AJAX.
After reloading the part I still want to have access to the form object.
How can I do this?
Best regards
I am not sure if your are using different terminology than I've heard, but what do you mean "still want to have access to the form object"?
Do you mean access to it in JavaScript? That should still work as long as you don't overwrite the form tags.
Do you mean in the html.erb code generating the partial? That doesn't really make sense, because that form_for object has already generated its html tags and gone out of scope. You need to use to the regular form of the helpers that takes the name of the object as the first parameter. There is no problem with this working with the tags generated by the form_for version of the helpers.
So, in your main page:
<%= form_for :person, #person, :url => { :action => "create" } do |f| %>
<%= f.text_field :name %>
<div id="reloadable">
</div>
<% end %>
And in your partial that fills that div:
<%= text_field :person, :name %>
No step 3.

Resources