I'm using Rails 5.2.2. I have a form with remote: true. I have a partial that displays shipping methods where I render nested shipping methods available for a quote. My form accepts nested attributes also.
My form works fine, but on update I am wanting to render the updated shipping methods if they have changed but since I pass the original form to my partial, I don't have that variable available on update. Here is my partial
_shipping_rates.html.erb
<h2> Shipping Rates</h2>
<div id="quote-shipping-rates">
<%= form.collection_radio_buttons(:shipping_method_id, quote.shipping_methods.sort_by(&:price), :id, :name, { checked: quote.shipping_method_id }) do |b| %>
<%= b.radio_button %>
<%= b.label %>
(<span class="text-red"><%= number_to_currency(b.object.price) %></span>)
<br />
<% end %>
On the initial page load I call the partial like this:
<%= render 'shipping_methods', :form => u , :quote => #quote %>
On update, I have the following file that executes JavaScript to update the DOM.
update.js.erb
I want to do something like this but I wasn't sure if there was some Rails way to recreate the form variable and pass it to the partial.
$("#quote-shipping-rates").html("");
$("<%= escape_javascript(render :partial => "shipping_methods", :form => u , :quote => #quote) %>").appendTo("#quote-shipping-rates");
Related
I have a situation where a Contact has many Leads and a Lead belongs to Profile polymorphically. I successfully rendered the form as such:
# _form.html.erb
<%= form_for #lead do |f| %>
<%= f.fields_for :contact do |builder| %>
<%= render "contact_fields", :f => builder %>
<%= render "leads_field", f: f %>
<% end %>
<% end %>
# lead_field.html.erb
<%= f.select :practice_type, PRACTICE_TYPES.collect {|type| [ type, type ] }
<%= f.fields_for :practice do |builder| %>
<%= render "#{#practice.class.name.underscore}_field", :f => builder %>
<% end %>
The above works fine with page load. However, a user can select a practice from dropdown menu and then I send ajax request to repopulate the form building an association with that practice:
$('#lead_practice_type').change(function() {
$.ajax({
url: "/leads/new",
data: {
profile_type : $(this).val()
},
dataType: "script"
});
});
The error occurs in new.js.erb:
$("#form_holder").html("<%= escape_javascript(render(:partial => "leads_field"))%>");
I want to only render that partial (if I render whole form, then all their contact information would be erased.). But because that partial contains a local f variable, it blows up:
NameError - undefined local variable or method `f'
I want to maintain the relations between the objects but also update just that one partial. But it appears I cannot do it through the new.js.erb script because when it renders the partial, there is no local variable 'f' passed.
Is there another alternative to achieve what I want?
I found this problem difficult to solve on two fronts. First, There is no way you can identify the form builder from the controller action and javascript. Second, although I am quite familiar with the railscasts episode http://railscasts.com/episodes/196-nested-model-form-revised?view=comments, in that episode he knew the fields_for to generate at compile time, and therefore he hid the markup in the data field of a link. Unfortunately, in my case I would not know the fields_for the user wants until runtime (when the browser loads and user selects an option).
I also realized that fields_for is important to maintain nice associations for form submission so that the create action would be simply: save the parent resource and it saves its associations.
The best solution I could come up with is as follows.
1) Create ALL the polymorphic associations with fields_for and hide the ones the user doesn't want via a select form field:
# template
<div id="runtime-profile">
<% Lead::TYPES.each_with_index do |association, index| %>
<div id="profile_<%= association %>">
<fieldset class="field-border">
<legend class="field-border"><%= association.underscore %></legend>
<%= f.fields_for :practice, build_builder_association(f, association) do |builder| %>
<%= render "#{builder.object.class.name.underscore}_field", :f => builder %>
<% end %>
</div>
<% end %>
</div>
# helper
def build_builder_association(f, association)
f.object.practice_type = association
f.object.build_practice({})
end
Use Javascript to hide and show the templates based on an option selected from dropdown, and then when form is submitted, remove the hidden elements from the DOM:
$("#new_lead").submit(function(){
$("[id^='profile_']:hidden").remove();
})
And that creates the original desired behavior I wanted. However, the solution is far from clean and any better suggestions are welcome.
So I'm new to rails and having a little bit of trouble my situation is that I have a products model that has some Images attached to it. I would like on my products page to have a button to create a new image via ajax.
Inside my products _form view i have:
<%= simple_form_for(#product) do |f| %>
<%= f.error_notification %>
<div class="inputs">
<%= f.input :name %>
<%= f.input :description, :input_html => {:class => "wysihtml5 span6", :style => "height:400px;"} %>
<%= f.association :images, label_method: :name, value_method: :id %>
<h4>Upload new file</h4>
</div>
<%= link_to 'Add Image', '/images/new', :remote => true, :"data-replace" => "#image-form" %>
<div id="image-form">
</div>
<div class="actions">
<%= f.button :submit %>
</div>
<% end %>
And it does successfully Load the page via ajax.
But I would like to load it without the layout. Is this possible?
Do I need to create a new action that renders the partial form and has no layout??
So I'm assuming you have it requesting and returning html and not js? There are a couple of thoughts I have on this:
If you only ever need for this request to return from an AJAX request, then you could simply tell the controller to always render layout: false
If you would like to allow the controller to return a full page on occasion, you can either accept an argument in the get request and change the output accordingly, or you can tell the controller to:
respond_to do |format|
format.html # will render default with no block passed
format.js { render layout: false }
end
This should just work with the code in your form right now, because the :remote => true tells the controller to return js if possible, but accessing images/new from your browser will request html.
(Requesting js does not mean that you actually have to return js, as I don't in this case; it's up to you to take the proper action with what is returned. Some might consider it bad form, though, to return something other than what is technically requested.)
You can use the following in your action. Let your action is new.
def new
#your code goes here
render :layout => false
end
I have a Rails 3.2 ajax form that creates a new Room for a Hotel. The new Room ajax form works correctly on the Room index page, but once I embed the new Room ajax form on a Hotel edit page, the form is submitted normally without using Ajax.
To create the new Room form, I use the following link on the Hotel edit.html.erb page:
<%#= link_to 'Add a Room', new_room_path(:hotel_id => #hotel.id), :remote => true, :class => 'new_room' %>
This loads the following form partial on to that same page:
<%= form_for #room, :remote => true, :html => { :class => "remote-form" } do |f| %>
<%= f.text_field :number %>
<%= f.text_field :size %>
<% if(params.has_key?(:'hotel_id')) %>
<% #hotel_id = params[:hotel_id] %>
<%= f.hidden_field :hotel_id, :value => #hotel_id %>
<% else %>
<%= f.collection_select(:hotel_id, Hotel.all, :id, :name) %>
<% end %>
<%= f.submit "Add this room", :class => 'room_create' %>
<%= link_to 'Cancel', '#', :class => "room_cancel" %>
<% end %>
And finally, I have the following in my create.js.erb (inside the rooms folder):
alert('Test creating a room');
var content = $('<%= escape_javascript(render(#room)) %>');
$("#room_list tbody").append(content);
The create.js.erb is not executed and the form is submitted regularly (non-ajax) and I finally arrive on the room show.html.erb page.
Why is the form be working correctly on the Units index page, but not on the associated Hotel edit page?
Even when you set :remote => true, Rails generates a form tag. Nested form tags are not supported by browsers and will result in unpredictable behavior.
You should rethink the views architecture here. Probably you can have the forms for the rooms outside of the form for the hotel, or maybe you can use fields_for and accepts_nested_attributes_for to edit children objects.
Here's a full example on how to use nested attributes: Nested Attributes Examples.
You cannot nest a form inside a form in HTML. When you click any submit button on a form, even if it's inside another form, only the outermost form will be properly submitted.
You can either use nested attributes to add the attributes for the room directly to the form, so that when the overall form is submitted so are all the rooms... or use a div and a link, instead of a form and a submit button.
Okay so I am quite new to Rails and am trying to do the following without success:
I have an Object (from my Active Record) containing a project, which contains n sub-projects, which contain n tasks. Now for each of these I want a partial view.
So I render from the project view the sub-project with the following code:
<%= render(:partial => 'subproject', :collection => #project.sub_projects) %>
Within my sub-project partial view called _subproject.rhtml (adding the code to a good ol Rails 1.2.3 project), so I can access the data like this:
<%= subproject.name %>
That will print out the name alright but when I try to generate a textfield this won't work:
<%= text_field 'subproject', 'name' %>
But this will:
<%= text_field 'subproject', 'name', :value => subproject.name %>
What am I doing wrong?
Edit: Changed title due to my problem is not passing the value but displaying it within a form field.
Edit2: As requested my controller code:
#project = Project.find(params[:id])
You can write this:
<%= render(:partial => 'subproject', :collection => #project.sub_projects) %>
as
<%= render :partial => #project.sub_projects %>
This will render every sub project with the sub_projects/_sub_project.html.erb partial. A little shortcut.
This:
<%= text_field 'subproject', 'name' %>
Says create a text_field called: subproject[name], but doesn't give it a value. You need to pass the value you want to set (the code that works).
The more idiomatic way of doing this now is with form_for:
<% form_for #subproject do |f| %>
<%= f.text_field :name %>
<% end %>
Or if you're using formtastic (https://github.com/justinfrench/formtastic), which is fantastic, you'd write:
<% semantic_form_for #subproject do |f| %>
<%= f.input :name %>
<% end %>
I hope this helps!
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.