I have a 'parent_id' which is successfully passed as parameter into a form page ("Create Child") here :
<li><%= link_to "Create Child", new_block_path(:parent_id => #block.id)%></li>
Logging the parameter gives :
Started GET "/blocks/new?parent_id=7" for ::1 at 2022-10-31 22:01:05 +0000
Processing by BlocksController#new as HTML
Parameters: {"parent_id"=>"7"}
I then have a form which calls a create method here :
def create
#block = Block.new(block_params)
if #block.save
redirect_to #block
else
render :new, status: :unprocessable_entity
end
end
using these block_params
private
def block_params
params.require(:block).permit(:title, :body, :parent_id)
end
end
But when I call the create function only :title and :body are present.
Printing the parameters shows :
Started POST "/blocks" for ::1 at 2022-10-31 22:01:17 +0000
Processing by BlocksController#create as TURBO_STREAM
Parameters: {"authenticity_token"=>"[FILTERED]",
"block"=>{"title"=>"this is a child of block 7",
"body"=>"this is a child of block 7"}, "commit"=>"Create Block"}
Filtered shows :title and :body are permitted correctly, but the URL parameter of parent_id has just vanished.
The rails guide states : "Submitted form data is put into the params Hash, alongside captured route parameters" - I just can't work this out. The parent_id parameter is there as it should be when the form is loaded, but when submitted it vanishes.
There are two actions, new and create, you could think they are separate.
So params from new won't be available in create automatically (in your case parent_id), you have to pass the params explicitly.
You could just add a hidden input in your form to pass parent_id:
<%= form_with model: #block do |f| %>
<%= f.hidden_field :paren_id, value: params[:parent_id] %>
<%= f.text_field :title %>
<%= f.text_field :body %>
<% end %>
Related
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:[]
So I've been at this a while and have tried a bunch of different methods. Essentially I have an over-arching property model and an associated deed model. From the properties#show view I have it displaying all associated deeds. I have a button in my property view that displays a modal (using AJAX) to create a deed associated to said model. All the steps work (even 'edit' and 'update' using AJAX from the properties view) except when trying to save the new deed I get an error message:
This form contains 1 error. Property must exist
I've tried passing the #properties.id through in different ways and I just can't seem to get it. I'll list all the relevant info I have and if more is needed just let me know.
Property Model
class Property < ApplicationRecord
has_many :deeds, dependent: :destroy
accepts_nested_attributes_for :deeds
end
Deeds Model
class Deed < ApplicationRecord
belongs_to :property
accepts_nested_attributes_for :property
end
Deeds Controller (Included edit and update actions)
def new
#deeds = Deed.new
#deeds.build_property
respond_to do |format|
format.html { render 'new'}
format.js
end
end
def create
#properties = Property.find(params[:deed][:property_id])
#deeds = #properties.deeds.new(deed_params)
if #deeds.save
flash[:success] = "Deed created successfully!"
respond_to do |format|
format.html { redirect_to deeds_path }
format.js
end
else
render 'new'
end
end
def edit
#deeds = Deed.find(params[:id])
respond_to do |format|
format.html { #deeds.save }
format.js
end
end
def update
#deeds = Deed.find(params[:id])
#properties = Property.find(#deeds.property.id)
#deeds.update_attributes(deed_params)
respond_to do |format|
format.html { redirect_to deeds_path }
format.js
end
end
private
def deed_params
params.require(:deed).permit(:property_id, :deed_number, :deed_context, :consideration, :recorded_date, :grantor, :grantee, :trustee)
end
new deeds link from properties#show view
<%= link_to fa_icon("plus", text: "Add Deed"), new_property_deed_path(#properties.id), remote: true, class: "btn btn-primary btn-large btn-ouline pull-right", locals: { property_id: #properties } %>
new.js.erb
$('#deeds-modal').modal("show");
$('#deeds-modal').html('<%= j render partial: "deeds/deeds_modal", locals: { property_id: #properties } %>');
_deeds_modal.html.erb partial Form
<div class="modal-body">
<%= bootstrap_form_for(#deeds, layout: :horizontal, remote: true) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.hidden_field :property_id, value: property_id %>
<%= f.text_field :deed_number, class: 'form-control' %>
<%= f.text_field :deed_context, class: 'form-control' %>
<%= f.text_field :consideration, class: 'form-control' %>
<%= f.text_field :recorded_date, class: 'form-control' %>
<%= f.text_field :grantor, class: 'form-control' %>
<%= f.text_field :grantee, class: 'form-control' %>
<%= f.text_field :trustee, class: 'form-control' %>
<%= f.form_group do %>
<%= f.submit "Save", class: "btn btn-primary" %>
<% end %>
<% end %>
</div>
server response upon deeds_modal form POST
Started GET "/properties/99/deeds/new" for 127.0.0.1 at 2017-05-30
23:24:48 -0400
Processing by DeedsController#new as JS
Parameters: {"property_id"=>"99"}
Rendering deeds/new.js.erb
Rendered shared/_error_messages.html.erb (0.4ms)
Rendered deeds/_deeds_modal.html.erb (5.6ms)
Rendered deeds/new.js.erb (7.3ms)
Completed 200 OK in 14ms (Views: 10.6ms | ActiveRecord: 0.0ms)
Started POST "/deeds" for 127.0.0.1 at 2017-05-30 23:24:55 -0400
Processing by DeedsController#create as JS
Parameters: {"utf8"=>"✓", "authenticity_token"=>"eaj9K...==", "deed"=>{"property_id"=>"", "deed_number"=>"69696969", "deed_context"=>"Bagel slaps", "consideration"=>"Considered", "recorded_date"=>"2017-05-31", "grantor"=>"", "grantee"=>"NipLips", "trustee"=>""}, "commit"=>"Save"}
(0.1ms) BEGIN
(0.1ms) ROLLBACK
Rendering deeds/new.js.erb
Rendered shared/_error_messages.html.erb (0.7ms)
Rendered deeds/_deeds_modal.html.erb (12.1ms)
Rendered deeds/new.js.erb (20.4ms)
Completed 200 OK in 32ms (Views: 30.6ms | ActiveRecord: 0.2ms)
So as you can see I've tried to pass through a local variable from the new link -> new.js.erb -> deeds modal form but I can't seem to pull the property_id into the new deeds object.
Is this even the correct approach for what I'm trying to do or am I just missing something? Hope this wasn't too long of a read and that I provided enough info... lol.
*Upon writing this post I clicked through some of the 'similar questions' on SO, which is where I got the #properties = Property.find(params[:deed][:property_id]) line from but I still get ActiveRecord::RecordNotFound (Couldn't find Property with 'id'=): upon submission. Also, thank you to anyone who takes the time to read this.
rails routes Update (only included relevant routes for brevity)
deeds GET /deeds(.:format) deeds#index
POST /deeds(.:format) deeds#create
new_deed GET /deeds/new(.:format) deeds#new
edit_deed GET /deeds/:id/edit(.:format) deeds#edit
deed GET /deeds/:id(.:format) deeds#show
PATCH /deeds/:id(.:format) deeds#update
PUT /deeds/:id(.:format) deeds#update
DELETE /deeds/:id(.:format) deeds#destroy
...
property_deeds GET /properties/:property_id/deeds(.:format) deeds#index
POST /properties/:property_id/deeds(.:format) deeds#create
new_property_deed GET /properties/:property_id/deeds/new(.:format) deeds#new
edit_property_deed GET /properties/:property_id/deeds/:id/edit(.:format) deeds#edit
property_deed GET /properties/:property_id/deeds/:id(.:format) deeds#show
PATCH /properties/:property_id/deeds/:id(.:format) deeds#update
PUT /properties/:property_id/deeds/:id(.:format) deeds#update
DELETE /properties/:property_id/deeds/:id(.:format) deeds#destroy
This should be you new action
def new
#deeds = Deed.new
#deeds.build_property
#properties = Property.find_by_id(params[:property_id]) # add this line
respond_to do |format|
format.html { render 'new'}
format.js
end
end
Update:
If you are not using the associated property anywhere else, you don't need to pass the locals and I don't suggest hidden_field as it can be easily modified, alternately you can do..
def new
#deeds = Property.find_by_id(params[:property_id]).deeds.new # add this line
#deeds.build_property
respond_to do |format|
format.html { render 'new'}
format.js
end
end
As the error says Property must exist, so, your intention is to print the property_id for a new record, but for some reason that's not happening.
As that value goes from your form_for directly to create a new "deed", then in must be setted on it, you do it, but you don't check if it's printing something or not, and it get's you a nil value that's not allowed because of the relationship between Deeds and Properties.
When you send the form, you can see the value is empty:
"deed"=>{"property_id"=>""}
How do you define which property_id must a new record have? You can create a variable within your new method and set an object to print within your form_for, it'll give you a value to proceed with a new record.
When you make a request to the new method you pass through the params the value for property_id:
Processing by DeedsController#new as JS
Parameters: {"property_id"=>"99"}
So I suppose you could use it instead setting a local variable which hasn't been initialized, maybe you can try with:
<%= f.hidden_field :property_id, value: params[:property_id] %>
I have a the following form I'm trying to submit (from the show method view):
<%= form_for(Photo.new, :remote => true, html: {multipart: :true}) do |f| %>
<%= f.label :title, 'Title' %>
<%= f.text_field :title %>
<%= f.label :image, 'Choose Image' %>
<%= f.file_field :image %>
<%= f.hidden_field :item_id, :value => #item.id %>
<%= f.submit 'Add' %>
<% end %>
And I'm trying to use the following create method:
def show
#item = Item.find(params[:id])
end
def create
#item = Item.find(params[:item_id])
#photo = Photo.new(photo_params)
redirect_to edit_photos_url, notice: 'Photo uploaded' if #photo.save
end
This is what the logs generate:
Started POST "/photos" for ::1 at 2015-07-03 21:17:10 -0400
Processing by PhotosController#create as HTML
Parameters: {"utf8"=>"✓", "photo"=>{"title"=>"sdb", "image"=># <ActionDispatch::Http::UploadedFile:0x007fe301a2ebf8 #tempfile=#<Tempfile:/var/folders/d8/hx2wgfwx7m77c6mjwx2pffcc0000gq/T/RackMultipart20150703-35083-rt86ai.png>, #original_filename="Screen Shot 2015-06-28 at 9.23.31 PM.png", #content_type="image/png", #headers="Content-Disposition: form-data; name=\"photo[image]\"; filename=\"Screen Shot 2015-06-28 at 9.23.31 PM.png\"\r\nContent-Type: image/png\r\n">, "item_id"=>"27"}, "commit"=>"Add"}
Can't verify CSRF token authenticity
Completed 404 Not Found in 1ms
ActiveRecord::RecordNotFound (Couldn't find Item without an ID):
app/controllers/photos_controller.rb:13:in `create'
The item_id seems to be submitted, yet it doesn't work ?
I've tried also implementing sessions, which would be more ideal. I've done the following in the create method of the items controller:
remember_item #item
Calling the method in the helper:
def remember_item(item)
cookies.permanent.signed[:item_id] = item.id
session[:item_id] = item.id
end
I've checked the session variables, and the :item_id did get passed correctly in the session. I've tried the following:
def create
#item = Item.find(session[:item_id])
#photo = #item.photos.build(photo_params)
redirect_to edit_photos_url, notice: 'Photo uploaded' if #photo.save
end
And this also doesn't work, giving the following error:
Couldn't find Item without an ID
I'd really like to get the latter to work. Suggestions?
The item_id is included in the photo params
#item = Item.find params[:photo][:item_id]
Should give you what you want.
If you look closely, what you are submitting is actually
params
=> {photo: {item_id: 1, **other_attrs}}
params[:item_id]
=> nil
params[:photo][:item_id]
=> 1
That is because item_id is in your form as a helper and the form helper thinks it is a property of photo.
I have a many-to-many relationship between Notes and Stacks. I am creating a form where a user can create a new note, with a title, body, and then a group of check boxes. The group of checkboxes are various Stacks. I want a user to be able to associate one or multiple Stacks with a particular note.
I am using the simple_form gem to do this. Everything is working except the Stacks will not save to the database. The title and body save, but not the Stacks. I have tested both sides of the relationship manually in the console, and they do yield the expected results -- it works.
One thing I notice when I watch what is going on in the Rails Server tab is Unpermitted parameters: stack_ids, as seen here:
Started POST "/notes" for 127.0.0.1 at 2014-10-06 16:00:21 -0600
Processing by NotesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"gMpbaYio0qkPLLrR6ICG0IJ7XNoy3Rn4RHLm3vwUU+I=", "note"=>{"title"=>"asdfs ", "body"=>"asdfasdf asfsadf ", "stack_ids"=>["1", "2", ""]}, "commit"=>"Create Note"}
Unpermitted parameters: stack_ids
My notes_controller.rb has these params:
def notes_params
params.require(:note).permit(:title, :body, :stack_id)
end
My stacks_controller.rb has these params:
def stacks_params
params.require(:stack).permit(:title, :description, :note_id)
end
Here is the form:
<%= simple_form_for #note, :html => { :class => 'form-horizontal' } do |f| %>
<%= f.input :title, placeholder: ":title", id: "note-form-title-field", class: "note-form-fields" %>
<%= f.input :body, placeholder: ":body", id: "note-form-body-field", class: "note-form-fields" %>
<%= f.association :stacks, as: :check_boxes %>
<%= f.button :submit %>
<% end %>
I have tried replacing :stack_id in the params with other variations, and always get the same result. Any ideas on how to get these Stacks to save to the database, associated with a note? Thanks.
This StackOverflow posting provides a detailed solution.
In summary, when declaring strong parameters, I needed to explicitly map the stack_ids key to an empty array in my notes_controller.rb file:
def notes_params
params.require(:note).permit(:title, :body, stack_ids: [])
end
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.