0

У меня есть 3 контроллера. Два возвращающихся специализированных предмета (статья, объявление) и один возвращающийся.Несколько контроллеров с логикой избыточного действия в рельсах

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 

метод show для контроллера статей содержит логику, которая бы должна быть продублирована в контроллере сообщений. Более конкретно:

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

После того как я принести ресурс, unique_id, я знаю, что тип и может расшириться оттуда, но я только хочу authorize и делать некоторые другие операции по ресурсам типа Article.

У кого-нибудь есть рекомендации, шаблоны или идеи, которые помогут убедиться, что изменения в этом ArticlesController#show не должны повторяться в диспетчере сообщений?

ответ

1

Вы можете использовать controller concerns для извлечения общей функциональности. Для вашего конкретного случая использования, вы можете иметь две проблемы:

  • AnnouncementsConcern, который имеет весь код, необходимый для борьбы с Announcements.
  • ArticlesConcern который имеет полный код для работы с Articles.

Тогда вы должны включить эти проблемы в контроллеры по мере необходимости. То есть вы должны включить AnnouncementsConcern в AnnouncementsController и ArticlesConcern в ArticlesController, затем включить обе проблемы в PostsController.

+0

К сожалению, чтобы вернуться к этому так поздно. Это похоже на классную идею, но мне трудно ее реализовать. Я не думаю, что понимаю, как PostsController должен вызывать методы в проблемах. Итак, у меня есть две части: (1) метод 'show', который имеет' authorize! (...) if @ resource.type == 'Article''. (2) 'deal_with_params (...)', который имеет такое же условное значение. Можете ли вы привести пример «СтатьиConcern», «PostsController» и, возможно, ArticlesController. – Yason

0

Вы можете высушить его, используя наследование. Это пример экстремально сухой базовый контроллер с помощью Pundit, Responders и 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 

Есть несколько действительно изящные фокусов здесь:

  • self.class.controller_name.classify.constantize использует конвенцию по конфигурации угадать модель, основанную на имя контроллера.
  • Использование callbacks before_action позволяет подклассам отказаться от использования skip_before_action или изменить поведение, объявив методы обратного вызова.
  • Использование yield позволяет подклассам входить в поток контроллера.
  • Формат JSON API использует тот же формат данных независимо от объекта, а не для рельсов по умолчанию, используя model_name.param_key в качестве ключевого ключевого ключа. Меньше живопись - это хорошая вещь.

Пример подклассов:

# 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

Вы можете, конечно, объединить это с модулем mixins (проблемы). – max