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類型資源的一些其他操作。

任何人都有建議,模式或想法,這些建議,模式或想法有助於確保在Posts Controller中不必重複對ArticlesController#show所做的更改?

回答

1

您可以使用controller concerns來提取常用功能。爲了您的具體使用情況,您可以有兩個顧慮:

  • 擁有所有應對Announcements所需的代碼的AnnouncementsConcern
  • 一個ArticlesConcern其中有處理Articles的所有代碼。

然後你會根據需要在控制器中包含這些問題。即您可以在AnnouncementsControllerArticlesConcern中包含AnnouncementsConcern,ArticlesController,然後在PostsController中包含這兩個問題。

+0

對不起,回來這個這麼晚。這看起來很酷,但我很難實現它。我不認爲我理解PostsController如何在關注點中調用方法。所以我有兩個部分: (1)'show'方法具有'授權!(...)if @ resource.type =='Article'。 (2)'deal_with_params(...)'具有相同的條件。 你可以給我一個'ArticlesConcern','PostsController'和ArticlesController的例子。 – Yason

0

您可以使用繼承將其乾燥。這是使用PunditRespondersjsonapi

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使用約定優於配置的猜測基礎上的模型控制器名稱。
  • 使用before_action回調可讓子類通過使用skip_before_action而退出或通過聲明回調方法來更改行爲。
  • 使用yield可讓子類訪問控制器的流程。
  • JSON API格式使用相同的數據格式,不管實體如何,而不是使用model_name.param_key作爲根參數鍵的rails默認值。減少自行車畫是一件好事。

一個子類的實例:

# 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