我有一个名为Page的基本模型,并且有很多基于页面的STI模型,例如
绘图
第
故事
等...
我为每个STI模型都有单独的控制器和视图,因为我需要根据模型类型自定义视图层,并为控制器和独立的控制器设置不同的逻辑。但是,我需要将所有模型的作者字段设置为当前用户。我如何在一个地方做到这一点?
例如,如果我在Page控制器上使用before_action并设置作者,它会影响@page实例变量,而我的DrawingsController正在使用@drawing,所以它不会保存我@drawing的作者,除非我在DrawingsController中重复相同的代码
修改
我的控制器层次结构是
DrawingsController< PagesController
PagesController< ApplicationController中
PagesController和DrawingsController都有7个restful动作。但是,PagesController上的操作没有任何用途,因为我不想让任何用户创建Pages。我只希望他们创建像Drawings这样的继承的STI类。
答案 0 :(得分:0)
您可以使用控制器层次结构中的一些约定和元编程来执行此操作:
def add_author
model = instance_variable_get(:"@#{controller_name.singularize}")
model.author = current_user
end
答案 1 :(得分:0)
我说实话,我不保证这个答案的最佳实践" - 但是如果它在某种程度上有所帮助,我会建议它。还要注意,在重新思考问题后,我意识到我在评论中的第一个建议的解决方案是错误的,第二个也不是很正确。所以我只发布了第二个建议的修改版本:
简答:让PagesController
处理大部分工作,并根据需要委托给特定于模型的东西的子控制器。正如phoet所说,你可以使用一些元编程(以不同的方式)来实现这一点。
class PagesController < ApplicationController
# pages controller stuff here
def create
@page = controller_name.classify.constantize.new(params[:page_params]) # I love Rails, don't you?
@page.author = current_user
handle_additional_create_actions
# For completeness of this example...
if @page.save
# render / redirect on success
else
# render errors
end
end
protected
# This method should be overwritten by sub controllers if needed
# Also, name this whatever you like, this is merely a verbose example for illustration purposes
def handle_additional_create_actions
# in the pages controller, this method does nothing
end
end
并且,如果特定于模型的控制器需要执行其他操作:
class DrawingsController < PagesController
# drawing controller stuff here
protected
def handle_additional_create_actions
@page.some_other_field = some_other_data
end
end
快速说明:请注意,在我的建议中,您要删除特定于模型的变量名称,这意味着我们没有@drawing
和@article
等,了。您的模型基本上都是Page
个对象的类型,因此我们将通过其通用名称作为约定来调用它。这样,当您要求DrawingsController
为Drawing
类执行特定操作时,它知道可以通过我们通常命名的@page
对象访问实例。
所以最终,PagesController
完成了繁重的任务,无论你处理哪种具体的模型类型。这样,在页面控制器中只能找到一般页面内容,并且在各自的具体控制器中可以找到绘图,文章或故事特定的内容。