The functionality I want to achieve with this is to have different fields based on the action the user is currently on.
The generic scaffold bundles the form into a partial and renders it in the new and edit actions. In a typical signup case, one may not want to update the password everytime the profile is updated. One way I used to solve this in the past is to create separate forms for new and edit; including the password in new only. Obviously, most fields repeat themselves. Is there a way to keep the partial but omit (thereby not updating) some fields on the form per action?
Let me assume you are building the form for user model.So in controller you will have
def new
#user = User.new
.....
end
def edit
#user = User.find(params[:id])
....
end
In the form partial use
<% if #user.new_record? %>
<%= f.field_type :field_name %>
<% end %>
This will not render the field during edit/update.
You can try it this way in one partial:
<% if params[:action] == "new" %>
<%= f.field_type :field_name %>
<% end %>
But you should think about the security because this doesnt keep away attackers from adding POST fields manually to write to fields that aret displayed as Fields on you form!
You can check whether the active record object being passed to the view (such as #user) is a new record or and old one using the method 'new_record?'. Based on this, you can decide what fields you want to display.
Alternatively, you could also have a partial and then pass it some value (most likely a Boolean) and based on that value you can decide which fields to render.
This can been done like:
render :partial => 'partial_name', :locals => {:bool => true}
And then in your partial do
<% if bool == true %>
<%= f.xyz_tag :name %> //whatever field you want
<% end %>
Related
I am having trouble displaying selected radio buttons in the edit action.
The app allows the user to create his own forms(surveys) and then apply them (answer them) to their children.
The issue:
When rendering the new action that allows the user to answer his form, forms display well, and save to database properly. Assigns the choices to the answer content.
On the other hand, edit action duplicates the choices, showing the ones that were selected AND new ones. I check the id of the answers and is rendering 2 times each answer.
Any ideas of how to fix this behaviour?
Relevant code:
_form.html.erb
<%= f.fields_for :answers do |a| %>
<% choices.each do |choice| %>
<%= a.radio_button :a_content, choice.c_description %>
<%= a.label :a_content, choice.c_description, :value => choice.c_description, class: 'no-margin' %>
<% end %>
<%= a.hidden_field :question_id, :value => question.id %>
<% end %>
answered_forms_controller.rb
def new
#child = current_user.children.find(params[:child_id])
#form = current_user.forms.find(params[:form_id])
#answered_form = #child.answered_forms.new(form_id: params[:form_id])
#answered_form.answers.build
end
def create
#answered_form = AnsweredForm.create(answered_form_params)
if #answered_form.save
flash[:success] = "Nuevo cuestionario " + #answered_form.form.f_title + " aplicado!"
redirect_to current_user.children.find(params[:child_id])
else
render 'new'
end
end
def edit
#child = current_user.children.find(params[:child_id])
#form = current_user.forms.find(params[:form_id])
end
def update
if #answered_form.update_attributes(answered_form_params)
flash[:success] = "Cuestionario para paciente actualizado!"
redirect_to #answered_form.child
else
render 'edit'
end
end
UPDATE:
I now figured out that the duplication occurs because in the new action I got #answered_form.answers.build, but if I remove that, I don't see the fields when creating a new answered_form.
I knew this because tried to put 2 times #answered_form.answers.build in the new action and then got duplicated when creating and triplicated when editing, so edit always adds the fields one more time than new action if you have something like #answered_form.answers.build in the new action.
I believe you should be able to do something like:
<%= f.collection_radio_buttons :a_content, choice, :id, :c_description, {}, { checked: choices.selected_response_id } %>
With this you should be able to generate your radio buttons for all your answers.
PS: the final hash has the condition for checking the selected option choices.selected_response_id you should change that to the selected response on your answer model.
Although Rails tries to infer the preselected radio button, it may not always work hence the reason for this final hash.
Read more here
If you want to preselect your radio button, it means you have already stored a boolean value in your database for this field. Just insert this value after the checked option inside your helper:
radio_button_tag("something", something, checked = value)
should work the same with f.radio_button
I'm working on a dynamic form in a Rails app, and I need to insert a variable number of records into a model in a single form submission. I've done this using PHP -> MySQL/Postgres before, but I have no idea how to do it in Rails.
Ultimately, users should be able to create any number of records to be inserted, but in my example below, I'm limiting it to 2... let me see if I can do that, first...
Here's the form - the ids all get a unique suffix because they are being populated dynamically from localStorage objects on submission.
new.html.erb
<%= form_for #entry, html: {id: :new_entry_form} do |f| %>
<% for i in 0..1 %>
<%= f.text_field :name, :id => 'name_#{i}' %>
<%= f.text_field :day, :id => 'day_#{i}' %>
<% end %>
<% end %>
Here's the associated controller - I'm sure that this is missing something, but I don't know what.
def new
#entry = Entry.new
end
def create
#entry = Entry.create(entry_params)
redirect_to "http://localhost:3000/entries"
end
private
def entry_params
params.require(:entry).permit(:name, :day)
end
Any help would be much appreciated.
Follow this link it shows how to create multiple object in one form submit:
http://vicfriedman.github.io/blog/2015/07/18/create-multiple-objects-from-single-form-in-rails/
I'm using Rails 4 collection_check_boxes in my forms. Filling out the form, I check some of the checkboxes. I've noticed that when the form refreshes after validation error, the checkboxes that were checked persists. Is this a feature of the tag? I couldn't find this information in the docs.
Checkbox form field code:
<div class="field">
<%= f.label "Area of Interest" %><br />
<%= f.collection_check_boxes :interest_ids, Interest.all, :id, :name do |b| %>
<div class="collection-check-box">
<%= b.check_box %>
<%= b.label %>
</div>
<% end %>
</div>
I do want the checkboxes to stay checked after form refresh but wanted to make sure it is a feature and not just a coincidence that is it working for me.
Any information would be helpful, thanks!
It's a feature of the tag as long as you use render :action instead of redirect_to :action to render your form upon a failed save/validation:
def create
#user = User.create(user_params)
if #user.valid?
redirect_to action: :show
else
render :new # #user gets passed to form_for
end
end
The key distinction is that when you use render :new, the #user model instance from your create action is passed to your form.
Now, in the new.html.erb view:
form_for #user do |f|
# Fields using the syntax f.text_field :attr_name, `f.collection_check_boxes :attr_name`, etc will reference the :attr_name in both #user to populate the value(s). Also, #user.errors[:attr_name] to show an error message, if present.
end
Basically, what's happening is in your controller you're calling one of save, create, validate, or valid? on your model. A failed validation after calling one of these methods prevents a save to the database, but the failed values are still present in the #user object. Also, the errors object is now populated with information on which attributes failed to updated and the reason why the validation failed.
Thus, when you re-render your form, you see the check boxes are still selected because they're populated from the values in model instance itself. Similarly any fields with matching errors should show an error for that field as well.
I don't think that the validation fail page refresh is the same action as a 'form refresh' unless you added language in your controller that would reset your form if the form fails to save.
When you check interest_ids the form and hit 'submit', it adds any checked value that passes validation into your model as a saved :interest_id value, so that saved value is what makes the checkboxes persist even if the whole form fails validation.
If you want to reset your form if any part of the form fails validation, I would suggest adding an if/else statement into your controller on the create action. #object.interest_ids = [] will reset the stored interest_ids on your object to an empty array, which will uncheck the boxes.
def create
#object = Object.new
if #object.save
redirect_to object_path(#object)
else
#object.interest_ids = []
render :new
end
end
I have a form where users enter profile info which is saved in the User model. I need to collect another piece of information from users at a later stage (on a different page). How do I collect this info and append it to the existing user record?
Here is my form code with the one additional input I need from the user. When I hit submit, it runs without error but the new field is not saved in my model. I ran the migration to add the field to the model.
<%= form_for #user, html: { method: :put }) do |f| %>
<div class="form-group">
<%= f.label :what_is_your_favorite_color %>
<%= f.text_field :color, class:"form-control" %>
</div>
<div class="form-group">
<%= f.submit "Submit", class:"btn btn-primary" %>
</div>
<% end %>
My controller update method is currently blank .. can you tell me what the update method should look like? The user is logged in so I need to find that user record (probably by id column?) and write or update the new input into the model.
def update
??
end
You first need to fetch your record, the pass it the params hash, and Rails will do the rest.
def update
#record = Record.find(params[:id])
if #record.update(record_params)
redirect_to #record
else
render :edit
end
end
If you are using Rails 4, you need to account for strong_parameters. So add the new attribute to the permitted attributes.
def record_params
params.require(:record).permit(:color, :and, :other, :attributes, :go, :here)
end
The above code assumes that the record id will be in the params hash, or in other words, you are using RESTful routes. If you are not, you may want to pass in the id from the session (if this is, as you say, a user record, and you are using Devise).
def update
#record = Record.find(current_user)
# ... the rest should be the same
end
I have a view with 3 forms, Schedules, Workouts and Exercises, all behaving like an edit form, each. And one submit(save) button in the all the view.
When I click on the save button. Every data changed on those forms should be updated after click.
What is the best solution for this ? Javascript updating each data separated ? How to do that ? Is there a more Rails way to do this easily ?
My difficulty is how to integrated all those models in one view, while all this is happening in the show(view) from the Student model.
If you're implementing something like a profile / edit page (where you can save all the records at once), the two ways I would look at would either be to save the forms via Ajax, or use a single submit method to handle them
Ajax
The ajax method would be the most conventional:
Every form you submit will go to the form's own update method in the backend
Each form could be handled by a single button, but it's best to split them up
#app/controllers/profile_controller.rb
def edit
#schedules = Schedule.all #-> not sure how many records you're using
#workouts = Workout.all
#exercises = Exercise.all
end
#app/views/profile/edit.html.erb
<%= form_for #schedule do |f| %>
<%= f.text_field :test %>
<% end %>
# -> other forms
<%= button_to "Save", "#", id: "save" %>
#app/assets/javascripts/application.js
$("#save").on("click", function() {
$("form").submit(); // we'll have to define the form to submit
});
Single
If you submit all the forms as one, you'll have to encase them all in a single form, as sending different errors. This could be achieved by using _, and handled in the backend by looping through the different params, saving each one individually.
I'd do this:
#app/controllers/application_controller.rb
def submit
types = %w(schedules exercises workouts)
for type in types do
type.constantize.update_attributes()
end
end
This allows you to create a form with the different data types submitted in the same action:
#app/views/profile/edit.html.erb
<%= form_tag profile_submit_path do %>
<%= fields_for #schedules do |f| %>
<%= f.text_field :title %>
<% end %>
# -> fields_for for the other objects
<% end %>
This will allow you to send the updated objects to your controller, allowing them to submit
If all of your models (Schedules, Workouts and Exercises) are associated, using fields_for should be a good option.
From the above link:
<%= form_for #person do |person_form| %>
First name: <%= person_form.text_field :first_name %>
Last name : <%= person_form.text_field :last_name %>
<%= fields_for :permission, #person.permission do |permission_fields| %>
Admin? : <%= permission_fields.check_box :admin %>
<% end %>
<%= f.submit %>
<% end %>
Read the guides.
You could have some simple javascript that iterates over all form tags and submits each of them.
Alternatively, if you are going to use javascript anyways, you could follow an AJAXish auto-save approach upon changing any field.
But I think it might be cleaner if you just had one form for multiple models, using fields_for.