0

J'ai une relation type many-to-many en utilisant has_many => :through, comme détaillé ci-dessous.Comment accéder au modèle de jointure sur une relation has_many: through

class member 
    has_many member_roles 
    has_many roles, :through => :member_roles 
end 

class role 
    has_many member_roles 
    has_man members, :through => :member_roles 
end 

class member_role 
    belongs_to :member 
    belongs_to :role 
    # has following fields: member_id, role_id, scope, sport_id 
end 

Ce que j'essaie de faire ici, c'est d'attribuer des rôles aux membres. Chaque rôle de membre a une portée qui, par défaut, est définie sur "Tout" mais si vous le souhaitez, vous pouvez définir "Sport". Si la portée est définie sur le sport, nous capturons également le sport_id, ce qui nous permet de restreindre l'évaluation de ce rôle à un sport particulier (autrement dit, nous ne pouvons gérer que les équipes de ce sport plutôt que les équipes de tous les sports). Cela semble assez simple.

J'ai installé mon update_member_roles une action quelque chose comme ceci:

def update 

    # Assume we passing a param like: params[:member][:roles] 
    # as an array of hashes consisting of :role_id and if set, :sport_id 

    roles = (params[:member] ||= {}).delete "roles" 
    @member.roles = Role.find_all_by_id(roles.map{|r| r["role_id"]}) 
    if @member.update_attributes params[:member] 
    flash[:notice] = "Roles successfully updated." 
    redirect_to member_path(@member) 
    else 
    render :action => "edit" 
    end 
end 

Les travaux ci-dessus assez agréable, il fixe les member_roles appropriés très bien ... mais comme je travaille sur le modèle de rôle et non la Modèle MemberRole Je suis un peu bloqué quant à la façon dont je peux accéder au modèle de jointure pour définir: scope et: sport_id.

Tous les pointeurs ici seraient très appréciés.

Répondre

1

Vous devez utiliser l'association member_roles au lieu de roles association.

def update 
    # The role hash should contain :role_id, :scope and if set, :sport_id 
    roles = ((params[:member] ||= {}).delete "roles") || [] 
    MemberRole.transaction do 

     # Next line will associate the :sport_id and :scope to member_roles 
     # EDIT: Changed the code to flush old roles. 
     @member.member_roles = roles.collect{|r| MemberRole.new(r)} 

     # Next line will save the member attributes and member_roles in one TX 
     if @member.update_attributes params[:member] 
     # some code 
     else 
     # some code 
     end 
    end 
    end 

Assurez-vous de joindre tout en une seule transaction.

L'autre possibilité est d'utiliser accepts_nested_attributes_for sur l'association member_roles.

+0

Type de. La seule chose est que cela ne supprime pas les anciens rôles si je change les rôles sélectionnés. Je suppose que je pourrais juste mettre @ member.member_roles.destroy_all au début de l'action, mais c'est un peu comme si je maniais un marteau pour casser une noix. – aaronrussell

+0

Vous pouvez supprimer les anciennes valeurs et affecter de nouvelles valeurs en changeant le code comme suit: '@member.member_roles = roles.collect {| r | MemberRole.new (r)} ' –

+0

J'ai modifié ma réponse pour résoudre votre problème. Puisque vous stockez des informations supplémentaires dans le modèle 'MemberRole' (à l'exception de' member_id' et 'role_id'), cette approche est raisonnable. –

0

On dirait que vous devriez regarder dans les attributs imbriqués:

+0

Salut, merci pour votre réponse, même si pour être honnête, je ne suis pas sûr que cela aide vraiment. J'ai regardé ces screencasts mais la situation ici est légèrement différente. – aaronrussell