0

J'ai 3 contrôleurs. Deux articles spécialisés de retour (article, annonce), et un retour soit.Contrôleurs multiples avec logique d'action redondante dans les rails

GET api/announcements/1 -- produces Announcement json 
GET api/articles/2  -- produces Article json 
GET api/posts/1   -- produces Announcement json 
GET api/posts/2   -- produces Article json 

la méthode show pour le contrôleur logique contient des articles qui doivent être dupliqué dans le contrôleur Messages. Plus précisément:

def show 
    deal_with_params(...) 
    authorize!(...) 
    render json: @resource 
end 

Après avoir chercher la ressource par unique_id, je sais que c'est le type et peut se lancer à partir de là, mais je veux seulement authorize et faire quelques autres opérations sur les ressources de type Article. Quelqu'un a-t-il des recommandations, des schémas, ou des idées qui permettraient de s'assurer que les changements à ce ArticlesController#show n'auraient pas besoin d'être répétés dans Posts Controller?

Répondre

1

Vous pouvez utiliser controller concerns pour extraire la fonctionnalité commune. Pour votre cas d'utilisation spécifique, vous pourriez avoir deux préoccupations:

  • Un AnnouncementsConcern qui a tout le code nécessaire pour traiter Announcements.
  • Un ArticlesConcern qui a tout le code pour traiter Articles.

Ensuite, vous devez inclure ces problèmes dans les contrôleurs si nécessaire. C'est à dire. vous devez inclure AnnouncementsConcern dans AnnouncementsController et ArticlesConcern dans ArticlesController, puis inclure les deux préoccupations dans PostsController.

+0

Désolé de revenir à si tard. Cela ressemble à une bonne idée, mais j'ai du mal à l'implémenter. Je ne pense pas que je comprenne comment le PostsController est censé appeler les méthodes dans les préoccupations. Donc j'ai deux pièces: (1) méthode 'show' qui a' authorize! (...) if @ resource.type == 'Article''. (2) 'deal_with_params (...)' qui a le même conditionnel. Pouvez-vous me donner un exemple de 'ArticlesConcern',' PostsController', et peut-être ArticlesController. – Yason

0

Vous pouvez le sécher en utilisant l'héritage. Ceci est un exemple d'un contrôleur de base extrêmement sec à l'aide Pundit, Responders et jsonapi

class ResourcesController < ApplicationController 

    respond_to :json 

    before_action :authenticate_user # use a secure by default model 
    before_action :set_resource, only: [:show, :update, :destroy] 
    before_action :authorize_resource, only: [:show, :update, :destroy] 
    before_action :set_resources, only: [:index] 

    def create 
    @resource = resource_class.create(permitted_attributes) do |r| 
     yield(r) if block_given? 
    end 
    respond_with(@resource) 
    end 

    def show 
    respond_with(@resource) 
    end 

    def index 
    respond_with(@resources) 
    end 

    def update 
    @resource.update(permitted_attributes) do |r| 
     yield(r) if block_given? 
    end 
    respond_with(@resource) 
    end 

    def destroy 
    @resource.destroy 
    respond_with(@resource) 
    end 


    private 

    def set_resource 
    @resource = resource_class.find(params[:id]) 
    end 

    def set_resources 
    @resources = policy_scope(resource_class) 
    end 

    def authorize_resource 
    authorize(@resource) 
    end 

    def resource_class 
    self.class.controller_name.classify.constantize 
    end 

    def permitted_attributes 
    whitelist = policy(@resource || self.class.resource_class) 
         .permitted_attributes 
    params.require(:data).require(:attributes).permit(whitelist) 
    end 
end 

Il y a quelques trucs vraiment chouettes ici:

  • self.class.controller_name.classify.constantize utilise convention sur la configuration de deviner le modèle basé sur la nom du contrôleur.
  • L'utilisation des rappels before_action permet aux sous-classes de se désactiver en utilisant skip_before_action ou de modifier le comportement en déclarant les méthodes de rappel.
  • L'utilisation de yield permet aux sous-classes de puiser dans le flux du contrôleur.
  • Le format de l'API JSON utilise le même format de données, quelle que soit l'entité au lieu des rails, par défaut, en utilisant model_name.param_key comme clé de paramètre racine. La peinture moins bikeshed est une bonne chose.

Exemple de sous-classes:

# Nothing special going on here 
class ThingsController < ResourcesController; end 

class ArticlesController < ResourcesController 
    def create 
    # taps into the yield 
    super do |article| 
     article.author = current_user 
    end 
    end 
end 

class StranglyNamedController < ResourcesController 
    def resource_class 
    Thing 
    end 
end 
+0

Vous pouvez bien sûr combiner cela avec des modules mixins (préoccupations). – max