I followed the Railscast for editing multiple records at the same time in one form. linked here: http://railscasts.com/episodes/165-edit-multiple-revised
This worked great for editing multiple onboarding_steps on the same form modal. Basically we mark the completion date of each step and hit save.
But now, one of these steps has a checklist of things to collect before it can be completed, and they want to put the checklist on the same form. And once I added in the <%= f.fields_for :onboarding_checkbox, onboarding_step.onboarding_checkbox do |checkboxes_form| %> section the form broke and threw a No route matches [POST] because the form is supposed to use PUT. For some reason adding in the nested attributes makes it want to do a POST instead of PUT.
This is it working properly before the nested attributes were added:
Started PUT "/onboarding_steps/update_multiple" for ::1 at 2018-06-15 15:25:25 -0500
Processing by OnboardingStepsController#update_multiple as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"",
"onboarding_steps"=>{"531"=>{"completed_date"=>""}, "280"=>{"completed_date"=>"02/09/2018"}}}, "commit"=>"Update"}
This is what it's doing with the nested section:
Invalid or incomplete POST params
Started POST "/onboarding_steps/update_multiple" for ::1 at 2018-06-15 15:47:08 -0500
ActionController::RoutingError (No route matches [POST] "/onboarding_steps/update_multiple"):
_edit_multiple.html.erb
<%= form_for :onboarding_steps, :url => update_multiple_onboarding_steps_path, :html => {:method => :put} do |form| %>
...
<% #onboarding_steps.each do |onboarding_step| %>
<%= fields_for "onboarding_steps[]", onboarding_step do |f| %>
... this is where it breaks the form ...
<% if onboarding_step.onboarding_checkbox.present? %>
<%= f.fields_for :onboarding_checkbox, onboarding_step.onboarding_checkbox do |checkboxes_form| %>
<%= submit_tag "Update", :class=>"btn btn-small btn-primary" %>
onboarding_steps_controller.rb
def edit_multiple
onboarding_step = OnboardingStep.find(params[:onboarding_step_id])
#onboarding_steps = OnboardingStep.includes(:onboarding_step_type).find(onboarding_step.group_steps.ids)
end
def update_multiple
logger.debug params
params.permit!
#onboarding_steps = OnboardingStep.update(params[:onboarding_steps].keys, params[:onboarding_steps].values)
#onboarding_steps.reject! { |s| s.errors.empty? }
if #onboarding_steps.empty?
redirect_to :back, notice: 'Update Successful'
else
render "edit_multiple"
end
end
which at the bottom does include onboarding_checkbox_attributes:[]
onboarding_step.rb has accepts_nested_attributes_for :onboarding_checkbox
routes.rb
resources :onboarding_steps do
resources :onboarding_checkboxes
member do
get "delete"
end
collection do
get :edit_multiple
put :update_multiple
end
end
Not sure where it's going wrong. It's Friday and my brain is fried
Had this same issue. Got around it by using each_with_index and assign an index to the record set:
In other words, instead of doing this:
<% #onboarding_steps.each do |onboarding_step| %>
<%= fields_for "onboarding_steps[]", onboarding_step do |f| %>
do this:
<% #onboarding_steps.each_with_index do |onboarding_step, index| %>
<%= fields_for "onboarding_steps[#{index}]", onboarding_step do |f| %>
Do not forget to include id in onboarding_checkbox_attributes:[]
Related
I hope the title, a blend of code and English, is sufficiently clear.
I have found very little documentation about this situation in my web searches... It seems even the official rails API guide and doc doesn't cover a form_for with a model that belongs to another.
I'm new to RoR, and it's fun! I am working with relationships and trying to create the form to make a new 'item' on a 'contest'. The problem is it is coming out completely blank, no HTML rendered whatsoever inside the body tags where the form should be.
Here is my routes.rb
resources :contests do
resources :items do
resources :votes
end
end
My item#new
def new
#contest = Contest.find params[:contest_id]
#item = Item.new
end
My new.html.erb
<%= render 'form', item: #item %>
And my form_for
<% form_for #item, url: {action: "create"} do |f| %>
<div class="field">
<%= f.label :name %>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :notes %>
<%= f.text_area :notes %>
</div>
<% end %>
Also, here is the route display
contest_item_votes_path GET /contests/:contest_id/items/:item_id/votes(.:format)
votes#index
POST /contests/:contest_id/items/:item_id/votes(.:format)
votes#create
new_contest_item_vote_path GET /contests/:contest_id/items/:item_id/votes/new(.:format)
votes#new
edit_contest_item_vote_path GET /contests/:contest_id/items/:item_id/votes/:id/edit(.:format)
votes#edit
contest_item_vote_path GET /contests/:contest_id/items/:item_id/votes/:id(.:format)
votes#show
PATCH /contests/:contest_id/items/:item_id/votes/:id(.:format)
votes#update
PUT /contests/:contest_id/items/:item_id/votes/:id(.:format)
votes#update
DELETE /contests/:contest_id/items/:item_id/votes/:id(.:format)
votes#destroy
contest_items_path GET /contests/:contest_id/items(.:format)
items#index
POST /contests/:contest_id/items(.:format)
items#create
new_contest_item_path GET /contests/:contest_id/items/new(.:format)
items#new
edit_contest_item_path GET /contests/:contest_id/items/:id/edit(.:format)
items#edit
contest_item_path GET /contests/:contest_id/items/:id(.:format)
items#show
PATCH /contests/:contest_id/items/:id(.:format)
items#update
PUT /contests/:contest_id/items/:id(.:format)
items#update
DELETE /contests/:contest_id/items/:id(.:format)
items#destroy
Here we go! My form_for call is inside a non-output tag. Changing <% to <%= reveals the output!
It seems that sometimes the answers to my questions end up being tiny details that are easy to miss when the problem seems complex. A word to those who stumble through here: consider the basics before re-iterating the complexities.
I had a form that I want user to answer every question, so I add a model-level validation.
I supposed if it pass validation, it should redirect to another page call "scenario" (I haven't finish it's view so it should show template missing). If it does not pass validation, it should render once again to the new page, remains the information already filled in, and show validation error.
But no matter I filled out those fields or not, when I click submit button, it always show me the index page instead of "new" or "scenario"(which should be template missing). It seems ignore what I have wrote in the action "create", and "create" is never been called.
I use rails c and insert a new record to test validation. It does work well, so I guess there is no problem for my model and validation.
I also try to make form_for redirect to "scenario" directly, to make sure it work well for form_for, and it does show templete missing to me, so there might be some problem for "create" itself. I really don't know what's going wrong.
<%= form_for #subject, :url => { :controller => 'appstores', :action => 'scenario' } do |f| %>
There is a similar question: rails form_for never invokes the create controller action to use redirect_to.
I had try to use "respond_with", not work. And also check my controller is named as appstroes_controller.rb with resources :appstores in routes.rb.
I use rails 4.2.4, ruby 2.0.0, and bootstrap 3, don't know whether the version cause those problem or not.
Any help would be appreciated, thanks!
app/controller/appstores_controller.rb
class AppstoresController < ApplicationController
def index
end
def new
#subject = Subjectinfo.new
end
def create
#subject = Subjectinfo.new(params[:subjectinfo])
if #subject.save
redirect_to :action => "scenario"
else # if not pass DB validation
render :action => :new
end
end
def scenario
end
end
app/view/appstores/new.html.erb
<%= form_for #subject, :url => { :controller => 'appstores', :action => 'create' } do |f| %>
<form class="form-horizontal">
<div class="form-group">
<%= f.label :username, "User Name:", :class=>"control-label", :for=>"username" %>
<% if #subject.errors[:username].presence %>
<span class="model-error"><%= #subject.errors[:username].join(", ") %></span>
<% end %>
<%= f.text_field :username, :autocomplete=>"off", :placeholder=>"User Name", :class=>"form-control", :id=>"username" %>
</div>
<div class="form-group">
<%= f.label :mobile_user, "Are you a mobile device user?", :class=>"control-label", :for=>"mobile_user" %>
<% if #subject.errors[:mobile_user].presence %>
<span class="model-error"><%= #subject.errors[:mobile_user].join(", ") %></span>
<% end %>
<div class="radio radio-primary">
<%= f.radio_button :mobile_user, "1", :id=>"mobile_user_1" %>
<%= f.label :mobile_user, "Yes", :class=>"control-label", :for=>"mobile_user_1" %>
</div>
<div class="radio radio-primary">
<%= f.radio_button :mobile_user, "0", :id=>"mobile_user_0" %>
<%= f.label :mobile_user, "No", :class=>"control-label", :for=>"mobile_user_0" %>
</div>
</div>
<div class="text-center">
<%= f.submit "NEXT", :class => "btn btn-default btn-outline btn-lg" %>
</div>
</form>
<% end %>
app/modle/subjectinfo.rb
(to support "attr_accessible" for rails 4, I had put "gem 'protected_attributes'" in my Gemfile)
class Subjectinfo < ActiveRecord::Base
validates_presence_of :username, :mobile_user
attr_accessible :username, :mobile_user
end
config/routes.rb
AppStore::Application.routes.draw do
match ':controller(/:action(/:id(.:format)))', :via => :all
root :to => "appstores#index"
resources :appstores
get "appstores/scenario"=>"appstores#scenario"
end
rake routes
Prefix Verb URI Pattern Controller#Action
/:controller(/:action(/:id(.:format))) :controller#:action
root GET / appstores#index
appstores GET /appstores(.:format) appstores#index
POST /appstores(.:format) appstores#create
new_appstore GET /appstores/new(.:format) appstores#new
edit_appstore GET /appstores/:id/edit(.:format) appstores#edit
appstore GET /appstores/:id(.:format) appstores#show
PATCH /appstores/:id(.:format) appstores#update
PUT /appstores/:id(.:format) appstores#update
DELETE /appstores/:id(.:format) appstores#destroy
appstores_rfscenario GET /appstores/rfscenario(.:format) appstores#rfscenario
Btw, here is what I saw form terminal, this is when I filled in all the fields.
Started POST "/appstores" for 127.0.0.1 at 2015-11-03 22:25:54 +0800
Processing by AppstoresController#index as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"7WV4Iw/0uHNSnuXpr8qa39oFEF9gZfKm8EyHGQna0o0=", "subjectinfo"=>{"username"=>"a1", "mobile_user"=>"1"}, "commit"=>"NEXT"}
Rendered appstores/index.html.erb within layouts/application (12.6ms)
Completed 200 OK in 91ms (Views: 88.0ms | ActiveRecord: 0.0ms)
Here is when I leave them blank, but no matter it is blank or not, it always render to index......
Started POST "/appstores" for 127.0.0.1 at 2015-11-03 22:25:54 +0800
Processing by AppstoresController#index as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"7WV4Iw/0uHNSnfuXpr8qa39oFEF9gZfKm8EyHGQna0o0=", "subjectinfo"=>{"esearch"=>""}, "commit"=>"NEXT"}
Rendered appstores/index.html.erb within layouts/application (12.6ms)
Completed 200 OK in 91ms (Views: 88.0ms | ActiveRecord: 0.0ms)
Remove the line match ':controller(/:action(/:id(.:format)))', :via => :all from your routes.rb file and never use it anymore. This pattern matches any route and it is on the first position, other routes in your file don't have a chance at all because of that.
I have in rails the following form in a view
<%= form_for (#account) do |f| %>
<%= f.label :comments,"Comments" %>
<%=f.text_area :comments %>
<%= f.submit "Confirm",:name=>"conf" %>
<%= f.submit "Reject" %>
<% end %>
When I submit the form I get the following hash in the log before the update of the database
Started PATCH "/accounts/12" for 127.0.0.1 at 2015-08-13 21:31:18 +0200
Processing by UseractionsController#answer_with_comments as HTML
Parameters: {"utf8"=>"✓", "account"=>{"comments"=>"mycomments"}, "conf"=>"Confirm", "id"=>"12"}
I am trying to access the input in the comments text area in the controller. I tried
params[:account][:comments]
but it does not seem to work. Could anyone give me the appropriate syntax? Thanks.
EDIT
This is my controller code. Right now the if loop return false and nothing is added to the database even though there is something submitted ("mycomments" see above in the param nested hash)
if params[:bankaccount][:comments]
#bankaccount.update_attribute(:comments, params[:bankaccount][:comments])
end
It is only the appropriate syntax for your view. It assumes that you have content field on your Comment model.
<%= form_for (#account) do |f| %>
<%= f.label :comments,"Comments" %>
<%= f.fields_for :comments do |ff| %>
<%= ff.text_field :content %>
<% end %>
<%= f.submit "Confirm",:name=>"conf" %>
<%= f.submit "Reject" %>
<% end %>
You also will have to declare nested attributes in your Account model and your params hash should be different.
You should watch these two Railscasts part 1 and part 2 to learn more about nested attributes.
Since you mention strong parameters as a tag you probably want to build this a bit differently.
private
def account_params
#the permit method might need to be altered depending on your model and view
params.require(:account).permit(:comments)
end
Somewhere else in your controller you would then do:
#bankaccount.update_attributes(account_params)
Please take a read: http://edgeguides.rubyonrails.org/action_controller_overview.html#strong-parameters
I have two methods in PersonsController- edit and update and a Person model:
def edit
#person=Person.find(params[:id])
end
def update
#person=Person.find(params[:id])
#person.update_attributes(params[:person])
end
and my edit.html.erb:
<h2> Edit info here!</h2>
<%= #person.name %>
<%= form_for #person, html: {mulitpart: true} do |f| %>
<p><%= f.text_field :location %></p>
<p><%= f.submit :submit , class: "btn btn-large btn-success" %></p>
<% end %>
and routes.rb:
resources :persons
But when I submit the form I get:
AbstractController::ActionNotFound
The action '5231d2491dba7fb057000004' could not be found for PersonsController
The 5231....... is id of a person.
Request Parameters:
{"utf8"=>"✓", "_method"=>"put", "authenticity_token"=>"3TL7nn4UxhxFoxETeooBMThhkE0VdMoGFpjN9sx4srk=", "person"=>{"location"=>"nagpur"}, "commit"=>"submit", "controller"=>"persons", "action"=>"5231d2491dba7fb057000004"}
What is wrong here? I'm using mongoid and rails 3.2.13.
Your final comment reveals the source of error.
For either #edit or #update, you should not set the params manually in hidden field, which is also unnecessary.
If using conventional RESTful routes as resources :persons, you edit route will look like GET /persons/1/edit where 1 is the param id. You can get this person in #edit as
#person = Person.find(params[:id])
Similarly, you can get the person again in #update whose route is PUT persons/1
#person = Person.find(params[:id])
Then the question is answered.
But there is one more problem in your code, the part you get the attributes for updating. Because the params of person's attributes are sent via form, all attributes are under params[:person]. Thus, to get the photo attribute, you should use
params[:person][:photo] # Not params[:photo]
I am trying to create lists and each has 2 attributes name and description.Database does create it and save it when using console but not using the website form.When checking the log file I found that website form does not post instead uses gets and is redirected to itself, How do I make the website form POST instead of GET so it gets stored in database.
Log file:
Started GET "/assets/jquery_ujs.js?body=1" for 127.0.0.1 at 2013-09-18 12:35:14 -0400
Served asset /jquery_ujs.js - 304 Not Modified (0ms)
Here is list controller:
def create
#list = Lists.new(params[:lists])
if #list.save
redirect_to #list
else
render 'new'
end
end
def update
if #list.update_attributes(params[:lists])
flash[:success] = "lists updated"
redirect_to #list
else
render 'edit'
end
end
def new
#list = Lists.new
end
This is the form for users to create list
<%= form_for #list, url: newlist_path(#list), html: { method: :put } do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
</br>
<%= f.label :description %>
<%= f.text_field :description %>
<%= f.submit "Create the List" %>
<% end %>
Your form_for helper is routing to the incorrect action. Try routing to the create action instead:
<%= form_for #list, url: {action: "create"} do |f| %>
I don't know if your controller's code excerpt you've pasted is complete, but you might missed to initialize list object for update. In your update action you have only
if #list.update_attributes(params[:lists])
but you are not initializing #list variable before. So you probably need something like
#list = Lists.find(params[:id])
You can also inspect your log file and verify what parameters are sent to controller.