Search code examples
mysqlruby-on-railsdatabasesimple-form

How to save selected values from one table column to another table column


I am new to Rails, and trying to learn. In my simple form I have created a drop down select with generated data from a table called professions. This part is working fine, and I can select multiple values. I'm using a mysql database.

When I click the submit button, I need it to save the chosen values to a column called my_professions in another table called users. I can’t figure out how to do this. I get this error

param is missing or the value is empty: user

My form

<%= simple_form_for @user, url: wizard_path, method: :put do |f| %>
<%= collection_select(:f, :professions_id, Profession.where.not(name: nil), :id, :name, {:multiple => true}, {:class=>'js-example-basic-multiple', :id=>'jsmultipleddd'}) %>
<%= f.submit "Save", :class => 'btn blue'  %> 
<% end %>

I have tried to add this to the user model

user.rb

class User < ApplicationRecord

has_many :professions
accepts_nested_attributes_for :professions

serialize :my_professions, Array
end

And this to the profession model

profession.rb

class Profession < ApplicationRecord
belongs_to :user
end


my params look like this

registration_steps_controller.rb

def user_params

  params.require(:user).permit(:gender,:practitioner_website, :public_health_insurance, clinic_images: [], professions: [])

end

application_controller.rb

def configure_permitted_parameters
  devise_parameter_sanitizer.permit(:sign_up, keys: [:gender, :practitioner_website, :public_health_insurance, clinic_images: [], professions: []])
  devise_parameter_sanitizer.permit(:account_update, keys: [:gender, :practitioner_website, :public_health_insurance, clinic_images: [], professions: []]) 
end

Solution

  • Start by getting rid of accepts_nested_attributes_for :professions. You don't need nested attributes for this.

    Then get rid of serialize :my_professions, Array. Serialize is a legacy hack to store complex data in string columns. You don't need or want this (ever), since associations should be stored in join tables in ActiveRecord - not array columns. That's how AR was designed to work and that's how relational databases where designed to work.

    Instead what you want is a join model. Which you can generate with:

    rails g model user_profession user:belongs_to profession:belongs_to
    

    Run the migration. You then setup the associations between users and professions:

    class User < ApplicationRecord
      # ...
      has_many :user_professions
      has_many :professions, through: :user_professions
    end
    
    class Profession < ApplicationRecord
      # ...
      has_many :user_professions
      has_many :users, through: :user_professions
    end
    

    Now this lets us associate users with professions by passing profession_ids.

    In a normal Rails form you would create the input with:

    <%= f.collection_select :profession_ids, Profession.all, :id, :name, multiple: true ... %>
    

    In SimpleForm use the association helper:

    <%= f.association :professions, ... %>
    

    Then whitelist the correct param:

    def user_params
      # don't jam this into one super long unreadable line
      params.require(:user)
            .permit(
              :gender, :practitioner_website, :public_health_insurance, 
              clinic_images: [], profession_ids: []
            )
    end