0

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

  • 1
    This answer shows how to properly create a HABTM relationship in ActiveRecord: http://stackoverflow.com/a/5120734/141774 – Todd Dec 31 '13 at 17:12
  • 1
    Questions: Do you want users to be able to have same skills with other users? This is so I know if habtm is the association you need. – Gjaldon Dec 31 '13 at 17:12

5 Answers5

2

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!

Community
  • 1
  • 1
Gjaldon
  • 5,534
  • 24
  • 32
1

If you set user to have_and_belong_to_many :skills also then this will work.

To create a new skill for a user do

user.skills.create!{...}

or to associate an existing skill with a user do

user << skill

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

user = User.find params[:id]

skills = user.skills

You can then do what you like to users skills

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

user.skills.each do |skill|

...

end

for more on HABTM association see http://guides.rubyonrails.org/association_basics.html#has-and-belongs-to-many-association-reference

Community
  • 1
  • 1
Nathan
  • 146
  • 1
  • 8
0

Forgive me If I get it wrong, try to fill in the gaps but I think you want something that looks like this.

controller

  def index
    #to fetch all skills associated to users (add where u.id=? to fetch for a single user)
    @users = User.select("u.name, s.name").
    from("users u, skills s, users_skills us").
    where("u.id = us.user_id").
    where("s.id = us.skill_id")
  end



  def new
    @user = User.new
    @skills = Skill.all
  end

  def create
    @user = User.new(params[:user])
    ...............................
  end

in the create form

<%= form_for @user do |f| %>
  <%= f.collection_select(:skill_ids, @skills,:id,:name)%>
  <%= f.submit "Save" %>
<% end %>
rav
  • 743
  • 6
  • 14
0

In order to use HABTM you need a join table named either users_skills or skills_users (not sure it matters). It should contain two integer columns named user_id and skill_id. You should create indices for them as well. In your User model you want has_and_belongs_to_many :skills and in your Skill model you want has_and_belongs_to_many :users.

Tom L
  • 3,389
  • 1
  • 16
  • 14
0

You need has_and_belongs_to_many on both sides of the realtionship.

class User
  has_and_belongs_to_many :skills

class Skill
  has_and_belongs_to_many :users

Alternatively (and better, in my opinion) would be to use has_many :through:

class User
  has_many :user_skills
  has_many :skills, through: :user_skills

class Skill
  has_many :user_skills
  has_many :users, through: :user_skills
user229044
  • 232,980
  • 40
  • 330
  • 338