How to have many-to-many relationship in rails

15,616

First, I assume, you have a user-model with a field "name" and a group-model with a field "name".

You need a model between users and groups. Let's call it grouping:

rails g model grouping user_name:string group_name:string

In the grouping-model (grouping.rb), you put:

belongs_to :user  
belongs_to :group

In the user-model:

has_many :groupings, :dependent => :destroy
has_many :groups, :through => :groupings

And in the group-model:

has_many :groupings, :dependent => :destroy  
has_many :users, :through => :groupings

In the _form file to edit or update a user's profile, you put:

<div class="field">
    <%= f.label :group_names, "Groups" %>  
    <%= f.text_field :group_names %>  
</div>

And, finally, the User-class must know, what to do with the information from the form. Insert into user.rb:

  attr_writer :group_names
  after_save :assign_groups

  def group_names
    @group_names || groups.map(&:name).join(' ')
  end

  private

  def assign_groups
    if @group_names
      self.groups = @group_names.split(/\,/).map do |name|
        if name[0..0]==" "
          name=name.strip
        end
        name=name.downcase
        Group.find_or_create_by_name(name)
      end
    end
  end

assign_groups removes whitespace and downcases all words, so you won't have redundant tags.

Now, you can show the groups for a user in the show file of his or her profile:

<p>Groups:
  <% @user.groups.each do |group|%>
    <%= group.name %>
   <% end %>
</p>

Hope, that helps.

Share:
15,616
Karan
Author by

Karan

Twitter: @karangb Engineer at Facebook 1st class MEng in Computer Science at Imperial College London.

Updated on July 18, 2022

Comments

  • Karan
    Karan almost 2 years

    I am new to rails, and am trying to set up a many-to-many relationship in my rails project. I have a small strategy, but I am not sure if its the correct way.

    Aim: I have a table of users, and a table of groups. Users can be part of many groups, and each group may have many users.

    Strategy:

    1. Set up User migration to have name:string
    2. Set up Group migration to have name:string
    3. Set up a Join table migration
    4. Set up User model such that it would have has_and_belongs_to_many :groups
    5. Set up Group model such that it would have has_and_belongs_to_many :users

    Would this be the correct strategy? Thanks!

    Railcast Summary from answer: For those that are interested - Railcast suggests you to use a has_many :through association since the strategy above has the limitation that you cannot add extra relation-specific information.

    check out: http://kconrails.com/tag/has_many/

  • Karan
    Karan about 12 years
    why do we have :dependent => :destroy for groupings?
  • tmaximini
    tmaximini about 12 years
    because the user will not be anymore in the group if you either delete the user or the group.
  • ferdynator
    ferdynator over 7 years
    Why not use the has_and_belongs_to_many relation? It would simplify the whole process if no additional fields are required in the intermediate table.