我有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
的更改?
答案 0 :(得分:1)
您可以使用controller concerns来提取常用功能。对于您的特定用例,您可能有两个问题:
AnnouncementsConcern
,其中包含处理Announcements
所需的所有代码。ArticlesConcern
,其中包含处理Articles
的所有代码。 然后,您可以根据需要在控制器中包含这些问题。即您将AnnouncementsConcern
中的AnnouncementsController
和ArticlesConcern
中的ArticlesController
包括在内,然后在PostsController
中包含这两项问题。
答案 1 :(得分: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
使用约定优于配置来根据控制器名称猜测模型。before_action
回调可让子类使用skip_before_action
选择退出,或通过声明回调方法来更改行为。yield
可让子类进入控制器流程。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