ruby-on-railsruby-on-rails-4

User has several skills


I want my users to have many skills. I do have a users and skills database table.

I used has_many_and_belongs_to association in user.rb

  has_many :skills

which I am not sure if its correct. And in skill.rb

  has_and_belongs_to_many :users

I also created a migration like that:

  def change
    create_table :user_skills do |t|
      t.belongs_to :users
      t.belongs_to :skills
   end

Is this correct?

So IF this is correct, how do I add new skills to my user? What is the general approach?

What I thought of,

In my users controller on update action I will be updating user's skill and update the user_skills table. How is this done?

Also How do I iterate through my user_skills table for a specific user? (in view)

Any guidance, resource, tip will be great help for me as its the first time i do something like this in Rails.

Thanks


Solution

  • In Rails, most would prefer to use has_many :through over habtm associations. Here's a guide on how to use it: ActiveRecord guide.

    A has_many through association for users and skills would look like this in your relevant models:

    class User < ActiveRecord::Base
      has_many :user_skills
      has_many :skills, through: :user_skills
    end
    
    class UserSkill < ActiveRecord::Base
      belongs_to :user
      belongs_to :skill
    end
    
    class Skill < ActiveRecord::Base
      has_many :user_skills
      has_many :users, through: :user_skills
    end
    

    Your migration would look like:

    def change
      create_table :user_skills do |t|
        t.references :user, index: true
        t.references :skill, index: true
      end
    end
    

    The indexes in the migration are for faster look-ups for using the reference_id. It's advisable to do that for all references.

    To add new skills to your user, you can refer to this SO answer.

    To update a user's skill, you could do this:

    @skill = @user.skills.find(params[:skill_id])
    @skill.update(skill_params)
    

    To create a user's skill, you could do this:

    @user.skills.create(skill_params)
    

    To add a skill to user, you could do this in your update action:

    @user.update(user_params)
    
    #app/views/users/edit.html.erb
    <%= f.select :skill_ids, Skill.all.collect {|x| [x.name, x.id]}, {}, :multiple => true %>
    

    When working with has_many through, you won't need to go through the user_skills table to get a specific user. You would, however, might need to get a specific user from a skill. To do this:

    @skill.users.find(user_id)
    

    Hope that helps!