'rails 7, form_with & params: How did 2 values get outside of the params[:modelname]?
I have a scenario where upon an admin-restricted creating a 'new' Invite, the admin can not enter 2 of the values. They are intended to be set upon a user 'registrars' at a later state. The creation works fine.
The 2 values in question are :responded and :attending (RA). Responded is set by default to false, and attending is not set and therefore defaults to nil.
I then have an edit page for the invite where the admin can update any information. The thinking is that this would be in case an invite makes a mistake that can not be undone, so the admin can set, or reset to default values.
The edit page works fine for all values except that the RA won't save to the DB. It raises no exceptions and in the logic of the invites_controller goes on as if it is saved.
Note: I can update and save these to values w/out any problems in rails c
I added a binding.break to see the params and here's where I'm presuming the problem lies:
>params[:invite] does not include RA. But if I do >params I can see it 'outside' of the ActionController::Parameters
(rdbg) params
#<ActionController::Parameters
{"_method"=>"patch",
"authenticity_token"=>"keSUCTMDKkOYCVzCRKwaFuQN6EL9of-0SlyEIKEn6OHr_8766q23xh0LhcpU1GzPoM1xdr8XmGfuRQAmMw4gzg",
"invite"=>#<ActionController::Parameters
{
"username"=>"Jim",
"titulation"=>"Mr Jim",
"guest_count"=>"1",
"escort_count"=>"1",
"password"=>""
}
permitted: false>,
"attending"=>"true",
"responded"=>"true",
"commit"=>"Update Invite",
"controller"=>"invites",
"action"=>"update",
"id"=>"8"
} permitted: false>
(rdbg) params[:invite] # ruby
#<ActionController::Parameters
{
"username"=>"Jim",
"titulation"=>"Mr Jim",
"guest_count"=>"1",
"escort_count"=>"1",
"password"=>""
}
permitted: false>
(rdbg)
Schema section here:
create_table "invites", force: :cascade do |t|
t.string "username"
t.string "titulation"
t.integer "guest_count"
t.integer "escort_count"
t.boolean "responded"
t.boolean "attending"
t.string "password"
t.string "password_digest"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
invite.rb (Model)
class Invite < ApplicationRecord
validates :username, presence: true, uniqueness: { case_sensitive: false }, length: { minimum: 3, maximum: 25 }
has_secure_password
attribute :responded, default: false
end
invite_controller.rb:
Note: because the 'new' page does not allow the admin to set the RA values I have invite_params for create and invite_extended_params for update ... def new if logged_in_admin? @invite = Invite.new else flash[:notice] = "Only Admins has access to that page." redirect_to root_path end end
def create
@invite = Invite.new(invite_params) # does not include responded & attending
if @invite.save
flash[:notice] = "Created new invite for #{@invite.titulation}"
redirect_to invite_path(@invite.id)
end
end
def show
@invite = Invite.find(params[:id])
end
def edit
@invite = Invite.find(params[:id])
if @invite.responded
flash.now[:alert] = "Warning, this invite has responded. Make sure you know what you're doing."
end
end
def update
@invite = Invite.find(params[:id])
if @invite.update(invite_extended_params) # includes responded & attending
binding.break
flash[:notice] = "Update was saved."
redirect_to invite_path(@invite.id)
else
flash.now[:alert] = "Something went wrong"
render 'edit'
end
end
private
def invite_params
params.require(:invite).permit(:username, :titulation, :guest_count, :escort_count, :password)
end
def invite_extended_params
params.require(:invite).permit(:username, :titulation, :guest_count, :escort_count, :password, :responded, :attending)
end
end
Edit page code:
<%= form_with(model: @invite, class: "shadow p-3 mb-3 bg-info rounded", local: true) do |form| %>
<div class="form-group row">
<%= form.label :username, class: "col-2 col-form-label text-light" %>
<div class="col-10">
<%= form.text_field :username, class: "form-control shadow rounded", placeholder: "Enter Unique username" %>
</div>
</div>
<div class="form-group row">
<%= form.label :titulation, class: "col-2 col-form-label text-light" %>
<div class="col-10">
<%= form.text_field :titulation, class: "form-control shadow rounded", placeholder: "Enter Titulation" %>
</div>
</div>
<div class="form-group row">
<%= form.label :guest_count, class: "col-2 col-form-label text-light" %>
<div class="col-10">
<%= form.number_field :guest_count, class: "form-control shadow rounded", placeholder: "How many Guests for this invite?" %>
</div>
</div>
<div class="form-group row">
<%= form.label :escort_count, class: "col-2 col-form-label text-light" %>
<div class="col-10">
<%= form.number_field :escort_count, class: "form-control shadow rounded", placeholder: "How many +1's for this invite?" %>
</div>
</div>
<div class="form-group row">
<%= form.label :password, class: "col-2 col-form-label text-light" %>
<div class="col-10">
<%= form.text_field :password, class: "form-control shadow rounded", placeholder: "Preset password" %>
</div>
</div>
<div class="form-group row">
<div class="col-2 col-form-label text-light"> Attendance:
<div class="col-10">
<%= radio_button_tag(:attending, true) %>
<%= label_tag(:attending, "Yes") %>
<%= radio_button_tag(:attending, false) %>
<%= label_tag(:attending, "No") %>
</div>
</div>
<div class="form-group row">
<div class="col-2 col-form-label text-light"> Responded:
<div class="col-10">
<%= radio_button_tag(:responded, true, @invite.responded) %>
<%= label_tag(:responded, "Yes") %>
<%= radio_button_tag(:responded, false, [email protected]) %>
<%= label_tag(:responded, "No") %>
</div>
</div>
<%= form.submit 'Update Invite' %>
<% end %>
Solution 1:[1]
The radio buttons are added to the html as tags without the form context so they are not included in the form's invite parameters.
To fix change them to use form.radio_button. For example, change ...
<%= radio_button_tag(:attending, true) %>
to
<%= form.radio_button(:attending, true) %>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | dbugger |
