I have a form that displays a set of inputs. I also have a button, and when clicked, I make an ajax request which is supposed to replace the existing inputs with a different set of inputs.
All my ajaxy linking stuff up works fine. The problem is that I'm using a form_for, so in order to display the new form inputs, I need the form builder instance.
View File
<%= simple_form_for #order do |f| %>
<div id="info">
<%= render 'my_first_form_fields_partial', f: f %>
</div>
<%= link_to 'Change inputs', change_inputs_path, remote: true %>
<% end %>
I'd like my js.erb to look like this, but f is only defined within the scope of the form in the view.
$('#info').html("<%= escape_javascript(render 'my_second_fields_partial', f: f) %>");
How can I work it so that I can get f into that partial somehow?
Can you use fields_for in your partial, and pass the #object to it? That way you don't need to pass a form builder?
partial:
<%= fields_for object do |f| %>
f.text_field :field_name
<% end %>
$('#info').html("<%= escape_javascript(render 'my_second_fields_partial', object: #object) %>
Many thanks to #flyfish, his answer helped me solved how to do ajax with nested attributes. I took #flynfish answer and tweeked it for my situation:
<%= fields_for object do |f| %>
<%= f.fields nested_object, child_index: Time.now.to_i do |builder| %>
<% end %>
$('#info').html("<%= escape_javascript(render 'my_second_fields_partial', object: #object), nested_object: #nested_object %>
The child_index is important for without it your params hash will build with [0] and will then overlay any other records built with the initial fields_for which starts at zero and increments from there.
Related
How would I go about creating a form that takes what user input as a value and just passes it to the controller without being connected to any model?
Something simple like i.e. calculating tax based on input salary, or other calculation like that, when I show the user a form, let them fill it, and when submitting it would go to the results
<%= form_with url: 'calculator#result' do |form| %>
<%= form.number_field :value, in: 1000.0..20000.0, step: 0.5 %>
<%= form.submit %>
<% end %>
i expected something like this to pass 'value' and redirect to calculator#result when submitting, but the button doesn't really do anything. whereas a form connected to a model seems pretty smart and does it
The form_tag Helper method is usually used for forms that are not linked to a model.
I think this should work:
<%= form_tag("/calculator/result", :method => "get") do %>
<%= label_tag(:value, "Value:") %>
<%= text_field_tag(:value) %>
<%= submit_tag("Submit") %>
<% end %>
So my form partial is loaded in my div id="secondary", which is hidden on first page load.
When the user hits a button with a class called toggleSidebar, then the _form.html.erb is shown.
I have overridden the partial to display a new form (even if update is pressed) when a user is not logged in like this:
<%= simple_form_for(Post.new, html: {class: 'form-horizontal' }) do |f| %>
As opposed to the regular version that looks like this, and is included in an if statement on this same partial:
<% if current_user and current_user.has_any_role? :editor, :admin %>
<%= simple_form_for(#post, html: {class: 'form-horizontal' }) do |f| %>
The real issue is in my view, when someone goes to Update, this is what happens when the user is logged out:
<%= link_to "Update", "#", class: "togglesidebar" %>
This is perfect, it executes the CSS and shows the empty form partial perfectly.
However, when a user is logged in, I want it to send the parameter parent_id: #post with the execution of the sidebar being toggled.
This is how it looks with a normal new_post_path view (i.e. the non-sidebar new post view):
<% if current_user %>
<%= link_to "Update", new_post_path(parent_id: #post) %>
<% end %>
This is what my PostController#New looks like:
def new
#post = Post.new(parent_id: params[:parent_id])
end
How do I either pass the params in the regular non new_post_path version, or tackle this another way?
You could probably use a helper method.
Just browse to the 'helper' directory under 'app' folder and create a file similar to [name]_helper.rb
In this file create a module by [name]Helper and declare your helper method in this module.
This module is automatically required by rails.
A small example might help you.
The code in the link_helper.rb under app/helper directory
module LinkHelper
def populate_link(link1, link2, parameter)
if current_user
public_send(link2, parameter)
else
link1
end
end
end
The code in views is
<%= link_to 'update', populate_link('#', 'new_requirement_path',parameter: 33) %>
I'm a bit confused by the question, but I think you may be just need to use a hidden field to pass the parent_id param back?
e.g./
<%= simple_form_for(Post.new, html: {class: 'form-horizontal' }) do |f| %>
<%= f.hidden_field :parent_id, { value: #post.try(:id) } %>
<% end %>
HTH?
I am also a bit confused, but the following railscast might help you. It shows how to embed data in an html-tag. You can probably do it the same way.
railscast-> passing data to javascript
Out of the possibilities there I'd recommend the data-attribute:
<%= simple_form_for,(Post.new, html: {class: 'form-horizontal' }, **data: {post_id: #post.id}**) do |f| %>
<% end %>
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.
I am trying to DRY up my Rails application a bit, so I would like to render a form in my show view but disable all input fields.
// show.html.erb
<%= form_for(#project) do |f| %>
<%= render 'fields', :f => f %>
<% end %>
What would be the best way to do that?
Thanks for any help.
Javascript
One way would be to do it using JS. Include a div with a specific class in the show view :
// show.html.erb
<div class='disable_input'>
<%= form_for(#project) do |f| %>
<%= render 'fields', :f => f %>
<% end %>
</div>
Then in your JS file :
$('.disable_input :input').prop('disabled', true);
Rails
If you want to actually generate it server side, you can pass a variable to your partial that will tell the partial if it has to add the disabled option on each field. It's a bit more work though!
Using a variable, you could do something like this :
<%= form_for(#project) do |f| %>
<%= render 'fields', :f => f, :disabled => true %>
<% end %>
In the partial :
<% disabled ||= false
#We do this so if disabled is not passed to the partial it doesn't crash.
# We default it to false
%>
<% # Then for all your fields, add disabled: disabled %>
<%= f.text_field :some_attribute, disabled: disabled %>
Form builder
Edit : actually, one way to avoid explicitly passing disabled everywhere would be to create a Custom form builder. There's some good resources talking about it, like this one : http://johnford.is/writing-a-custom-formbuilder-in-rails/
In this example, it's done for onkeypress, shouldn't be hard to adapt for your case!
You can wrap all fields in <fieldset disabled>
// show.html.erb
<%= form_for(#project) do |f| %>
<fieldset disabled>
<%= render 'fields', :f => f %>
</fieldset>
<% end %>
You can use stylesheets for this thing.
The show action might be in controller say 'Project', hence you might be having a file in stylesheets with the name of your controller.
Now enclose your form in show.html.erb in a div, and give it a unique id ,say 'disable_input', that you wont be giving to any element in any page.
Now disable all input fields in you css under this div. You can write it like this..
disable_input input{
# whatever you want to do
}
Hence no need to code.
What is the difference between form_for and form_tag? Is anything different for form_remote_for and form_remote_tag?
You would use form_for for a specific model,
<% form_for #person do |f| %> # you can use f here
First name: <%= f.text_field :first_name %>
Last name : <%= f.text_field :last_name %>
<% end %>
Form_tag create basic form,
<%= form_tag '/person' do -%>
<%= text_field_tag "person", "first_name" %>
<% end -%>
form_for prefers, as its first arg, an activerecord object; it allows to easily make a create or edit form (to use it in a "new" view you should create an empty instance in controller, like:
def new
#foo = Foo.new
end
It also passes a form variable to the block, so that you don't have to repeat the model name within the form itself. it's the preferred way to write a model related form.
form_tag just creates a form tag (and of course silently prepare an antiforgery hidden field, like form_for); it's best used for non-model forms (I actually only use it for simple search forms or the like).
Similarly, form_remote_for and form_remote_tag are suited for model related forms and not model related forms respectively but, instead of ending in a standard http method (GET, POST...), they call an ajax method.
All this and far more are available for you to enjoy in the FormHelper and PrototypeHelper reference pages.
EDIT 2012-07-13
Prototype has been removed from rails long ago, and remote forms have completely changed. Please refer to the first link, with reguard to the :remote option of both form_for and form_tag.
These should be similar:
<% form_for #person do |f| %>
<%= f.text_field :name %>
<% end %>
and:
<%= form_tag '/person' do %>
<%= text_field_tag "person[name]" %>
<% end %>
If you want to submit the same params to the controller, you would have to define this explicitly.