ruby-on-railshas-many-throughcollection-select

Setting limitations across has_many through models


Those are my models:

class User < ActiveRecord::Base
  has_many :memberships
  has_many :groups, through: :memberships
end

class Group < ActiveRecord::Base
  has_many : memberships
  has_many :users, through: :memberships
  belongs_to :group_type
end

class Membership < ActiveRecord::Base
  belongs_to :user
  belongs_to :group
end

class GroupType < ActiveRecord::Base
  has_many :groups
end

I would like to assign groups to users. there are several types of groups, users can choose only one group from each type. in the view there should a select tag for each group type (a user don't have to be a member of each of the group types).

I can add a type_id column to the membership model and create a instance for each group for each new user, and then update rows, with something like (for type 1):

<%= form_for (@user) do |f|
<% @membership = Membership.where (user_id: :@user.id,  group_type: :1) %>
<%= f.collection_select (:membership, :group_id, Group.all.where(type: 1), :id, :name) %>  
<% end %>

(not sure that it will work)

anyway I'm sure there is a better way.. how can I connect the models with the one group for each type limitation? (with, ofcourse, a way to edit existing memberships).

I would appriciate any assistance...

Thank you!


Solution

  • Your model structure look good. You could also include the group_type in the membership and than validate against uniqueness.

    class Membership < ActiveRecord::Base
      belongs_to :user
      belongs_to :group
      belongs_to :group_type
    
      validates :user_id, uniqueness: { scope: [:group_id, :group_type_id],
    message: "can only join one group of this type." }
    end
    

    The form should create a membership.

    <%= form_for (Membership.new) do |f|
      <%= f.hidden_field :user_id, value: @user.id %>
      <%# your selection for a group %> 
    <% end %>
    

    In the controller you have to load the group from the DB, than add the group_type_id to params and .save -> The validation will handle the rest.