Home > Net >  rails 7, form_with & params: How did 2 values get outside of the params[:modelname]?
rails 7, form_with & params: How did 2 values get outside of the params[:modelname]?

Time:04-01

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 >
    <%= form.label :username, class: "col-2 col-form-label text-light" %>
    <div >
      <%= form.text_field :username, class: "form-control shadow rounded", placeholder: "Enter Unique username" %>
    </div>
  </div>

  <div >
    <%= form.label :titulation, class: "col-2 col-form-label text-light" %>
    <div >
      <%= form.text_field :titulation, class: "form-control shadow rounded", placeholder: "Enter Titulation" %>
    </div>
  </div>

  <div >
    <%= form.label :guest_count, class: "col-2 col-form-label text-light" %>
    <div >
      <%= form.number_field :guest_count, class: "form-control shadow rounded", placeholder: "How many Guests for this invite?" %>
    </div>
  </div>

  <div >
    <%= form.label :escort_count, class: "col-2 col-form-label text-light" %>
    <div >
      <%= form.number_field :escort_count, class: "form-control shadow rounded", placeholder: "How many  1's for this invite?" %>
    </div>
  </div>

  <div >
    <%= form.label :password, class: "col-2 col-form-label text-light" %>
    <div >
    <%= form.text_field :password, class: "form-control shadow rounded", placeholder: "Preset password" %>
    </div>
  </div>

  <div >
    <div > Attendance:
    <div >
      <%= radio_button_tag(:attending, true) %>
      <%= label_tag(:attending, "Yes") %>
      <%= radio_button_tag(:attending, false) %>
      <%= label_tag(:attending, "No") %>
    </div>
  </div>

    <div >
    <div > Responded:
    <div >
      <%= 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 %>

CodePudding user response:

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) %>
  • Related