在我的Rails 4应用程序中,我有两个控制器具有几乎相同的操作:
class InvoicesController < ApplicationController
...
def load
@invoice = Invoice.find_by(:download_code => params[:id])
if @invoice
respond_to do |format|
format.pdf { |pdf| render_pdf("attachment") }
end
else
flash[:notice] = "Not found."
redirect_to signin_path
end
...
end
class RemindersController < ApplicationController
...
def load
@reminder = Reminder.find_by(:download_code => params[:id])
if @reminder
respond_to do |format|
format.pdf { |pdf| render_pdf("attachment") }
end
else
flash[:notice] = "Not found."
redirect_to signin_path
end
...
end
为了干掉我的代码,将这两者结合起来的最佳实践方法是什么?
感谢您的任何想法。
答案 0 :(得分:2)
我首先要让Reminder
和Invoice
扩展共享的超类,或者将模块混合到它们的共享功能中。我更喜欢后者,因为我更喜欢委托和mixins继承。
其次,您应该使用以下方法创建一个混合到控制器中的模块:
def download_helper(your_superclass_instance)
if @your_superclass_instance
respond_to do |format|
format.pdf { |pdf| render_pdf("attachment") }
end
#all the rest where you replace @reminder or @invoice with @superclass_instance
end
将包含download_helper
的模块混合到您的控制器中,然后您可以像这样简单地调用它:
def download
@invoice = Invoice.find_by(:download_code => params[:id])
download_helper(@invoice)
end
显然对RemindersController
也一样。
我很确定您可以做一些聪明的元编程,即使find_by
调用download_helper
的第一个Invoice
部分,也可以简单地传入Reminder
或{{1}类本身。但我必须研究如何做到这一点,而且我认为过于过于聪明,并且在这个过程中使事情变得不那么容易接近过度工程。
答案 1 :(得分:1)
将共享代码放在application_controller.rb中或创建一个模块并将其包含在需要的控制器类中。
答案 2 :(得分:1)
当你构建一个重用它的方法时,很容易使它变得多态(在不同的上下文中可以使用而不需要特别改编)。我想首先向ApplicationController添加一个实例方法,这样可以使用rails约定从控制器名称中轻松推断出模型类。 #controller_name是一个有用的rails方法,可以为你完成部分工作。
def model_class
controller_name.singularize.constantize
end
然后,您的方法可以调用@object = model_class.find_by(:download_code => params[:id])
,而不是专门引用它需要搜索的类。之后,我同意上述答案,然后您可以将方法提取到超类或共享模块。
您选择的其中一个可以通过您应用的当前复杂性来指导。如果这是您现在需要的唯一共享方法,只需将其粘贴在ApplicationController中,但如果该类已经忙或者您尝试提取其他共享方法,请将代码移动到新模块并将其混合到两个控制器中。
答案 3 :(得分:1)
要扩展@errata,请将before_action:download放在应用程序controller.rb的顶部