'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