I have a nested form that uses a has_many relationship. In my form view, I use a partial for the field inputs and pass along the FormBuilder object.
form.html.haml:
- form_for #record do |f|
.field
= container do
- f.fields_for :strings do |s|
= render :partial => 'string_fields', :locals => {:s => s}
_string_fields.html.haml:
= s.hidden_field :id
= s.hidden_field :language_id
.field
%h3
= t(:name)
= s.text_field :name, :size => 50
.field
%h3
= t(:description)
= s.text_area :description, :rows => 6
This works as it should; however, I'd like to add functionality in AJAX to dynamically add another set of fields using RJS, and when I try to render the partial through RJS, obviously s isn't defined (I don't know what I'd pass through the :locals hash).
Is there some way to properly add field dynamically to a field set defined by fields_for, or do I have to reimplement my partial without using the helpers?
It's possible to add fields dynamically with your current implementation, look at:
http://railscasts.com/episodes/197-nested-model-form-part-2
for inspiration
Related
I am working on a Rails App, for which the model logic is not in the frontend, and it retreives data from the backend API.
I was referring to the form helpers guide , and in Section 2.2 Binding a Form to an Object , it explains about the binding of form to model object so new and edit form can be a single page by binding the form elements to model object.
articles_controller.rb:
def new
#article = Article.new
end
The corresponding view using form_for looks like this
articles/new.html.erb:
<% form_for :article, #article, :url => { :action => "create" }, :html => {:class => "nifty_form"} do |f| %>
<%= f.text_field :title %>
<%= f.text_area :body, :size => "60x12" %>
<%= submit_tag "Create" %>
<% end %>
http://guides.rubyonrails.org/v2.3.11/form_helpers.html
While in my code, I get the values via API call as a JSON object.
def view_request
#request_type = "View"
id = params["id"]
rest_resource = RestClient::Resource.new( ENV['TEST_API'] + "/" + id, :verify_ssl => false )
request = rest_resource.get :Authorization => cookies.signed[:remember_token], :content_type => 'application/json'
#response = JSON.parse(request)
render " request"
end
What would be the best way to create forms for both new and edit in this scenario ?
I think you want to check out form_tag. Then inside that form, you'll use tag variants, like text_field_tag.
You'll have to do a little extra work to get your one form to manage both new and edit, but it's not too bad.
BTW, in an effort to fully decouple my views from my models, I exclusively use form_tag and never access models or model instances in my views. It's a little nuts, but it helps me protect views from changes in my models.
I am building a rails application using ActiveAdmin, and want to build a form for a custom action in the controller. I am trying to pass #listings from a collective_action to the rendered file, allowing me to edit multiple records at once. The #listings are based on an ActiveRecord query which draws record IDs from the URL.
It seems to be successfully accessing the parameters from the URL, and querying the database. When the form is served to the browser however, it is not able to produce the values of listing.title. Any ideas?
Here is my Listing.rb:
ActiveAdmin.register Listing do
collection_action :batch_upload do
ids = params[:id]
#listings = []
#listings = Listing.find(ids)
render template: 'listings/edit_batch'
end
end
Here is my edit_batch.html.haml:
= semantic_form_for :listing, :url => {:controller => 'listings', :action => 'batch_upload'}, :html=>{:method=>:put} do |f|
-#listings.each do |listing|
=f.hidden_field :id, :value => listing.id
=f.input :title, :value => listing.title
=f.submit "Submit"
If the form is correctly displaying listing.id but not listing.title then I suspect the record does not have title set, or listing does not have a title attribute.
To check, run the Rails console and find the record using the id from the form:
$ Listing.find(1)
Check the returned object to see whether it is missing the title.
I changed the code to the input so that it accesses its html directly and it worked:
=f.input :title, :input_html => { :value => listing.title }
Using Formtastic's inputs block might help simplify the inputs for each listing. Doing so will allow the form to create attribute fields for each Listing object.
# edit_batch.html.haml
= semantic_form_for :listing, :url => {:controller => 'listings', :action => 'batch_upload'}, :html=>{:method=>:put} do |f|
- #listings.each_with_index do |listing, index|
f.inputs for: listing, for_options: { index: index } do |l|
= l.input :id, as: :hidden
= l.input :title
= f.submit "Submit"
The :for and :for_options scope inputs fields to a specific object.
I have a reusable field template, called _field.html.haml, that looks like (in haml):
= f.label field
= f.send(field_type, field, :class => field_type)
The advantage of this is that it can be called from a parent form template and provides reusability. This lets me dynamically render form fields based on a field type. The calling template looks like:
= form_for(#model) do |f|
= render :partial => 'field', :locals => { :field => :first_name, :field_type => :text_field }
= render :partial => 'field', :locals => { :field => :last_name, :field_type => :text_field }
How could I add auto-generating of the placeholder text based on the label text to this _field.html.haml template? Maybe the correct question is what is the code that the label hdlper uses to convert the field name to an capitalized english phrase?
I.e. code would look like:
= f.send(field_type, field, :class => field_type, :placeholder => #INSERT CODE HERE to get friendly placeholder text)
the label_tag method uses `String#humanize" to make it look nicer (http://api.rubyonrails.org/classes/String.html#method-i-humanize). So in your example you could do:
= f.send(field_type, field, :class => field_type, :placeholder => field.to_s.humanize)
As previously mentioned in the comments, you should have a look at available form-builders. They abstract a lot of pain associated with making nice forms. Some links are:
https://github.com/plataformatec/simple_form
https://github.com/justinfrench/formtastic
Intro
I have an object #organization that has_many :quick_facts
Basically, I want to produce a _form for each :quick_fact but with one save button, that saves all of the quick_facts.
My two problems:
First Problem:
My quick_facts are not prepopulated with their information. They only appear as blank for each quick_fact I have.
Second Problem
A save button appears on every single form
My sad sad attempt :
- for quick_fact in #organization.quick_facts
- fields_for :quick_facts do |f|
= f.error_messages :header_message => FORM_ERROR_HEADER_MESSAGE, :message => FORM_ERROR_MESSAGE
= f.label :quick_fact, 'QuickFact'
%br/
= f.select :quick_fact, QUICK_FACTS, {}
%br/
= f.submit 'save', :class => 'button'
You really just want one form here, since you want to submit everything at once.
Here is what I would recommend:
Use a partial to render the label and the text option for the quick fact (if you want it to be text). You want this partial to be rendered once per quick fact, so use the :collection option on the render method to specify the collections of quick facts. Each partial will get its own local copy of whatever quickfact you are on, and a variable called quickfact_counter will also be created.
In addition, you will want to use the :locals option to pass the form to the partial as a local variable, so that you can do f.label, f.text_area
So, in conclusion, your new form will be something like this:
<% form_for #organization do |form| %>
<%= render :partial => "partial_name", :collection => #organization.quick_facts, :locals => {:form => form} %>
<%=form.submit 'save', :class => 'button'%>
<% end %>
Then your partial will just have
<%= form.label :quick_fact, 'QuickFact' %>
<%= form.text_field :quick_fact %>
If you wanted to get even fancier you could use a layout to render the form and have it defer to the partial, but this should be enough to get you started. Being able to pass a collection to a partial is one of my favorite Rails features.
In my project i have this combo box, and it works perfectly:
<%= collection_select #project, #project.clients.id, #project.clients, :id, :name %>
My simple and quick question is, how can i render this in a partial, I'm using this and it's not working...
<%= render :partial => "clients", :collection => #project.clients, :locals => {:project => #project }%>
and the partial code is:
<%= collection_select :project, clients.id, clients, clients.id, clients.name %
Try this within your partial:
<%= collection_selection project, project.clients.id, project.clients, :id, :name %>
(When you refer to template instance variables that are passed in to the partial as locals, use the non-symbol form of the variable name.)