2009-08-19 9 views
1

J'ai les modèles suivants:Dans Rails, comment utiliser les actions RESTful pour une ressource qui est la jointure dans une relation plusieurs à plusieurs?

class User < ActiveRecord::Base 
    has_many :subscriptions 
end 

class Subscription < ActiveRecord::Base 
    belongs_to :user 
    belongs_to :queue 
end 

class Queue < ActiveRecord::Base 
    has_many :subscriptions 
end 

Je veux avoir des méta-données dans la classe d'abonnement et permettre aux utilisateurs de conserver les détails de chacun de leurs abonnements avec chaque abonnement méta-données. Les files d'attente génèrent des messages et ceux-ci sont envoyés aux utilisateurs qui ont des abonnements à la file d'attente. Comme je le vois la ressource que je veux avoir est une liste d'abonnements, c.-à-d. L'utilisateur remplira un formulaire qui a toutes les files d'attente auxquelles ils peuvent s'abonner et mettra des métadonnées pour chacun d'eux. Comment puis-je créer une ressource RESTful Rails pour y parvenir? Ai-je mal conçu ma classe d'abonnement?

J'ai actuellement dans mon routes.rb:

map.resources :users do |user| 
    user.resources :subscriptions 
end 

Mais cela fait chaque abonnement une ressource et non la liste des abonnements une seule ressource.

Merci.

Répondre

2

Cela peut se faire assez facilement en utilisant accepts_nested_attributes_for et fields_for:

d'abord dans le modèle de l'utilisateur que vous effectuez les opérations suivantes:

class User < ActiveRecord::Base 
    has_many :subscriptions 
    accepts_nested_attributes_for :subscriptions, :reject_if => proc { |attributes| attributes['queue_id'].to_i.zero? } 

    # if you hit scaling issues, optimized the following two methods 
    # at the moment this code is suffering from the N+1 problem 
    def subscription_for(queue) 
    subscriptions.find_or_initialize_by_queue_id queue.id 
    end 

    def subscribed_to?(queue) 
    subscriptions.find_by_queue_id queue.id 
    end 

end 

qui vous permettra de créer et enregistrements enfants de mise à jour à l'aide du poseur de subscriptions_attributes . Pour plus de détails sur les possibilités voir accepts_nested_attributes_for

Maintenant, vous devez configurer les routes et contrôleur pour effectuer les opérations suivantes:

map.resources :users do |user| 
    user.resource :subscriptions # notice the singular resource 
end 

class SubscriptionsController < ActionController::Base 

    def edit 
    @user = User.find params[:user_id] 
    end 

    def update 
    @user = User.find params[:user_id] 
    if @user.update_attributes(params[:user]) 
     flash[:notice] = "updated subscriptions" 
     redirect_to account_path 
    else 
     render :action => "edit" 
    end 
    end 

end 

Jusqu'à présent, cela est la norme de la tourbière, la magie se produit dans les vues et comment vous mettre en place les params: app/views/abonnements/edit.html.erb

<% form_for @user, :url => user_subscription_path(@user), :method => :put do |f| %> 
    <% for queue in @queues %> 
    <% f.fields_for "subscriptions[]", @user.subscription_for(queue) do |sf| %> 
     <div> 
     <%= sf.check_box :queue_id, :value => queue.id, :checked => @user.subscribed_to?(queue) %> 
     <%= queue.name %> 
     <%= sf.text_field :random_other_data %> 
     </div> 
    <% end %> 
    <% end %> 
<% end %> 
+0

Merci! J'ai fait les changements que vous avez suggérés avec quelques ajustements et ai les bases fonctionnant. Un problème est que je reçois des lignes dans les abonnements avec 0 comme queue_id. C'est quand je décoche la case à cocher. Est-il possible de supprimer ces lignes lorsqu'elles ne sont pas cochées? – Greg

+0

essayez la ligne suivante dans le modèle utilisateur: accepte_nested_attributes_for: abonnements,: reject_if => proc {| attributes | attributs ['queue_id']. to_i.zero? } – derfred

Questions connexes