jjasonn
jjasonn

Reputation: 41

Rails 4 simple_form params not being saved to database

As a novice to RoR I am making a site that allows clients to fill out a large form online. The form includes some nested models, but my issue is with the client not being saved to the database on the form submit.

From looking at my server it seems that params is picking up on the client information, but when sql action starts it doesn't insert any of the information into the database. Although it says it commits the transaction, my client in rails console have all nil attributes.

    Started POST "/clients" for 192.168.1.114 at 2014-08-16 23:40:14 -0700
Processing by ClientsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"2tPnVc7Aj5mMdd9ZnXVuFHHs3CprND6QZ8qyCxSC674=", "client"=>{"name"=>"Jon", "birthdate"=>"August 2 1990", "has_guardian"=>"0", "guardian"=>{"name"=>"", "phone_number"=>"", "relationship"=>"", "address"=>"", "birthdate"=>""}, "gender"=>"male", "relationship"=>"single", "address"=>"25 Oak Road, LA, CA, 90003", "home_phone"=>"3105636778", "home_phone_manner"=>"leave_message_with_info", "preferred_home_phone"=>"false", "confidential_home_phone"=>"false", "cell_work_phone"=>"3104556721", "cell_work_phone_manner"=>"leave_message_with_info", "preferred_cell_work_phone"=>"true", "confidential_cell_work_phone"=>"true", "email"=>"[email protected]", "confidential_email"=>"true", "written_communication"=>"use_email", "family_contact"=>{"name"=>"Lily Mod", "phone_number"=>"3109776663"}, "additional_info"=>"Test", "created_at(1i)"=>"2014", "created_at(2i)"=>"8", "created_at(3i)"=>"17", "employer"=>"Polly", "occupation"=>"Sales", "prescriptions"=>"None", "medicines"=>"None", "allergies"=>"None", "conditions"=>"None"}, "commit"=>"Create Client"}
    Unpermitted parameters: has_guardian, guardian, family_contact, created_at(1i),       created_at(2i), created_at(3i)
  (0.1ms)  begin transaction
  SQL (0.4ms)  INSERT INTO "clients" ("additional_info", "created_at", "updated_at")          VALUES   (?, ?, ?)  [["additional_info", "Test"], ["created_at", Sun, 17 Aug 2014 06:40:14 UTC  +00:00], ["updated_at", Sun, 17 Aug 2014 06:40:14 UTC +00:00]]
  (0.6ms)  commit transaction
 Redirected to http://192.168.1.114:3000/
 Completed 302 Found in 59ms (ActiveRecord: 1.5ms)

When I pry inside my clients#create it shows at @client with all nil attributes, but when I call a method like name on @client it returns the value that is in the params.

26:   def create
27:     @client = Client.new(client_params)
=> 28: binding.pry
29:     respond_to do |format|
30:       if @client.save
31:         format.html { redirect_to root_path, notice: 'Client was successfully created.' }
32:         format.json { render controller: :static_pages, action: 'home', status: :created, location: root_path }
33:       else
34:         format.html { render action: 'new' }
35:         format.json { render json: @client.errors, status: :unprocessable_entity }
36:       end
37:     end
38:   end

[1] pry(#<ClientsController>)> @client
=> #<Client id: nil, name: nil, email: nil, home_phone: nil, home_phone_manner: nil, cell_work_phone: nil, cell_work_phone_manner: nil, written_communication: nil, confidential_email: nil, additional_info: "test", birthdate: nil, gender: nil, relationship: nil, employer: nil, occupation: nil, medicines: nil, allergies: nil, conditions: nil, created_at: nil, updated_at: nil, preferred_home_phone: nil, confidential_home_phone: nil, preferred_cell_work_phone: nil, confidential_cell_work_phone: nil, prescriptions: nil, address: nil>
[2] pry(#<ClientsController>)> @client.name
=> "Jon"

My relevant Clients Controller:

 def new
   @client = Client.new
 end

 def create
   @client = Client.new(client_params)

   respond_to do |format|
     if @client.save
       format.html { redirect_to root_path, notice: 'Client was successfully created.' }
       format.json { render controller: :static_pages, action: 'home', status: :created,     location: root_path }
     else
       format.html { render action: 'new' }
       format.json { render json: @client.errors, status: :unprocessable_entity }
     end
   end
 end
 def client_params
   params.require(:client).permit(:name, :email, :address, :home_phone, :home_phone_manner,
                                 :cell_work_phone, :cell_work_phone_manner,
                                 :written_communication, :confidential_email,
                                 :additional_info, :birthdate, :gender, :relationship,
                                 :prescriptions, :employer, :occupation, :medicines,
                                 :allergies, :conditions, :preferred_home_phone,
                                 :confidential_home_phone, :preferred_cell_work_phone,
                                 :confidential_cell_work_phone)
 end

My routes file:

  match '/contact', to: 'static_pages#contact', via: :get
  match '/about', to: 'static_pages#about', via: :get
  match '/contact', to: 'static_pages#about', via: :get

  match '/forms', to: 'clients#new', via: [:get, :post]

  resources :clients
  resources :family_contacts
  resources :guardians

My Client model, I realize I haven't completed everything to get the associations working but I am concerned with just saving a client for now:

  class Client < ActiveRecord::Base

    has_one :guardian

    has_many :family_contacts

    accepts_nested_attributes_for :family_contacts
    accepts_nested_attributes_for :guardian

    attr_accessor :name, :email, :birthdate, :gender, :address
    attr_accessor :home_phone, :home_phone_manner, :confidential_home_phone, :preferred_home_phone
    attr_accessor :cell_work_phone, :cell_work_phone_manner, :confidential_cell_work_phone, :preferred_cell_work_phone
    attr_accessor :written_communication, :confidential_email
    attr_accessor :relationship, :employer, :occupation
    attr_accessor :prescriptions, :medicines, :allergies, :conditions

    def has_guardian?
      self.guardian.present?
    end

 end

My form is very long, but Iv'e tried to simplify it by taking out a lot of the styling and labels:

    <%= simple_form_for(@client, defaults: { required: false }, html: { class: 'form-inline' }) do |f| %>

    <%= f.input :name, label: "Patient's Name:", placeholder: "First & Last" %>

    <%= f.input :birthdate, label: "Birthdate:", placeholder: "January 1 2000" %>

    <%= f.input :has_guardian?, label: "Are you under the age of 18?", as: :boolean %>

      <%= f.simple_fields_for Guardian.new do |g| %>
        <%= g.input :name, label: "Name of Gaurdian", placeholder: "First & Last" %>
        <%= g.input :phone_number, label: "Phone # of Guardian", as: :tel %>
        <%= g.input :relationship, label: "Relationship to Patient" %>
        <%= g.input :address, label: "Guardian's Address" %>
      <% end %>

    <%= f.collection_radio_buttons :gender, [['male', 'Male'], ['female', 'Female']], :first, :last %>

    <%= f.collection_radio_buttons :relationship, [['single', 'Single'], ['married', 'Married'], ['widowed', 'Widowed'], ['seperated', 'Seperated'], ['domestic_relationship', 'Domestic Relationship']], :first, :last %>

    <%= f.input :address, lable: "Home Address:", placeholder: '25 Oak Road, Los Angeles, CA, 90003' %>

    <%= f.input :home_phone, label: "Home Phone #", as: :tel %>

    <%= f.collection_radio_buttons :home_phone_manner, [['leave_message_with_info', 'Leave message with detailed information.'], ['leave_message_with_callback', 'Leave message with call-back number only.']], :first, :last %>

    <%= f.collection_radio_buttons :preferred_home_phone, [[true, 'Yes'], [false, 'No']], :first, :last %>

    <%= f.collection_radio_buttons :confidential_home_phone, [[true, 'Yes'], [false, 'No']], :first, :last %>

    <%= f.input :cell_work_phone, label: "Cell/Work Phone #", as: :tel %>

    <%= f.collection_radio_buttons :cell_work_phone_manner, [['leave_message_with_info', 'Leave message with detailed information.'], ['leave_message_with_callback', 'Leave message with call-back number only.']], :first, :last %>

    <%= f.collection_radio_buttons :preferred_cell_work_phone, [[true, 'Yes'], [false, 'No']], :first, :last %>

    <%= f.collection_radio_buttons :confidential_cell_work_phone, [[true, 'Yes'], [false, 'No']], :first, :last %>

    <%= f.input :email, label: "Email:", as: :email %>

    <%= f.collection_radio_buttons :confidential_email, [[true, 'Yes'], [false, 'No']], :first, :last %>

    <%= f.collection_radio_buttons :written_communication, [['mail_home', 'Mail to my home address (above).'], ['mail_work', 'Mail to my work address.'], ['fax_to_home', 'Fax to me home phone (above).'], ['use_email', 'Email me to the above email address.']], :first, :last %>

  <%= f.simple_fields_for FamilyContact.new do |c| %>

      <%= c.input :name, label: "Name:", placeholder: "First & Last" %>

      <%= c.input :phone_number, label: "Phone #", as: :tel %>

      <%= c.input :name, label: "Name:", placeholder: "First & Last" %>

      <%= c.input :phone_number, label: "Phone #", as: :tel %>

  <% end %>

  <%= f.input :additional_info, label: "Additional Information:", as: :text %>

    <%= f.input :created_at, label: "Date", as: :date %>

    <%= f.input :employer, label: "Employer:" %>

    <%= f.input :occupation, label: "Occupation:" %>

    <%= f.input :prescriptions, label: "Current Prescription Medications:" %>

    <%= f.input :medicines, label: "Over the Counter Medications:" %>

    <%= f.input :allergies, label: "Allergies to Medications" %>

    <%= f.input :conditions, label: "Other Medical Conidtions" %>

    <%= f.input :created_at, label: "Date", as: :date %>

  <%= f.simple_fields_for Guardian.new do |g| %>
    <%= g.input :name, label: "Name of Gaurdian", placeholder: "First & Last" %>
    <%= g.input :birthdate, label: "Birthdate of Guardian", placeholder: "January 1 2000" %>
  <% end %>

  <%= f.input :name, label: "Patient's Name:", placeholder: "First & Last" %>
  <%= f.input :birthdate, label: "Birthdate:", placeholder: "January 1 2000" %>

  <%= f.submit %>

Sorry for the length of the files, but I really appreciate any help. Thanks

Upvotes: 1

Views: 1637

Answers (1)

Richard Peck
Richard Peck

Reputation: 76774

Here's the error:

Unpermitted parameters: has_guardian, guardian, family_contact, created_at(1i), created_at(2i), created_at(3i)

Although the error above is for strong_params, I think it's a deeper issue which we need to resolve. As you're new, let me detail how this works for you...


Attributes

The model you have are heavily populated with attr_accessor. attr_accessor is a way to create "virtual attributes" in Ruby / Rails, as it defines a custom getter and setter method, which will essentially define the "attributes" for use on the system

The problem you have is attr_accessor, in the simplest of terms, will not permit your data to be saved in the database. This will be one of the bigger issues you have - you need to get rid of any attr_accessors which override your database attributes

This is demonstrated here:

INSERT INTO "clients" ("additional_info", "created_at", "updated_at") VALUES (?, ?, ?) [["additional_info", "Test"], ["created_at", Sun, 17 Aug 2014 06:40:14 UTC +00:00], ["updated_at", Sun, 17 Aug 2014 06:40:14 UTC +00:00]]

This basically shows that only additional_info, created_at and updated_at are populating the database.

You should remove the attr_accessor methods from your Client model:

#app/models/client.rb
class Client < ActiveRecord::Base

    has_one :guardian

    has_many :family_contacts

    accepts_nested_attributes_for :family_contacts
    accepts_nested_attributes_for :guardian

end

Unpermitted

The unpermitted parameters issue is caused mainly by your non-permission of these in your strong params hash. You'll need to add them here:

#app/controllers/clients_controller.rb
Class ClientsController < ApplicationController
   private

   def client_params
      params.require(:client).permit(..., :has_guardian, :guardian, :family_contact, :created_at(1i), :created_at(2i), :created_at(3i))
   end
end

Although this is definitely the case, I feel there is a massive problem with the number of attributes you're trying to pass through. It's not against convention or anything, but validating all of those attributes each submit is surely going to cause a problem?

I'd say its unworkable - you'd be better splitting it up into manageable associated models / objects, though I'll leave that up to you to work out

Upvotes: 1

Related Questions