我正在编写库存管理Rails应用程序。我有class Product < ActiveRecord::Base
,class Foo < Product
和class Bar < Product
。 Foo和Bar的行为略有不同,但使用单表继承对他们来说非常好。
问题在于控制器和视图。目前我将它们完全分开,这有效,但包含大量重复的代码。通过复制两个目录并将@foo
,@foos
和Foo
替换为@bar
,@bars
和{{1 }}。当我添加新功能时,添加它们两次会很烦人。而且,当然,并不是Rails方式不干。
那么这里的正确方法是什么?对于控制器...我应该制作一个Bar
,然后只使用元编程魔法来ProductsController
或Foo
?还是使用继承?对于视图,我应该只有产品视图,但是使用聪明的路由使它看起来像我有单独的(和RESTful)Bar
和/foos
路径?
感谢。
答案 0 :(得分:0)
对于控制器继承将是一个很好,干净和可维护的方法。定义基本控制器中的所有主要逻辑,并使用可在继承控制器中覆盖的虚方法替换对对象的任何调用:
class Product < ApplicationController
def resource
nil
end
def new_resource
nil
end
def do_something
resource.do_something
end
def new
@resource = new_resource
end
end
class Foo < Product
def resource
@foo
end
def new_resource
Foo.new
end
end
继承是非常可维护的,非常干净和清晰,是这类工作的不错选择。
对于视图,您可以为所有常见视图部分创建一个shared
目录,这是另一种非常常见的方法,并且允许您以最小的麻烦对URL进行完全RESTful控制。如果你的对象也有类似的方法,那么视图不需要知道它正在处理什么类。
在上面的控制器中,访问foos / new的用户将启动对new_resource的调用,该调用将构建一个新的Foo实例并将其作为@resource返回到页面。
#View:
<%= render 'shared/product_details', :locals => {:product => @resource} %>
答案 1 :(得分:0)
如果您拥有完全相同的控制器方法和视图,则可以将其移至产品 - 这样,您将拥有Product
,@product
和@products
。由于它是STI
,因此Foo
和Bar
上没有ID重复,因此成员路由也可以。此外,由于模型不同,鸭子打字将负责为每个模型调用正确的方法。
然后,您可以将两个子模型中未重复的所有内容移动到特定控制器。
答案 2 :(得分:0)
根据OP的进一步澄清,我现在有了自己的想法。
模型继承适用于其他OOP语言,但在Ruby中不是必需的。在这种情况下,我认为最好的解决方案是使用Module。
你仍然需要两个型号Foo和Bar,它们甚至可以有不同的属性。
然后,定义模型和控制器的常用方法
# lib/product_model.rb
module ProductModel
def product_method_a
end
def product_method_b
end
end
# lib/product_controller.rb
module ProductController
def show
@obj = @model.constantize.find(params[:id])
render 'products/show' # need to explicitly specify it because this is general
end
def index
@objs = @model.constantize.scoped
render 'products/index' # need to explicitly specify it because this is general
end
end
然后,在Foo和Bar中使用这些方法,并根据需要添加自定义方法。
class Foo < ActiveRecord::Base
include ProductModel
def serial_number
# Foo's way
end
end
class Bar < ActiveRecord::Base
include ProductModel
def serial_number
# Bar's way
end
end
对于控制器。
class FoosController < ApplicationController
@model = "foo"
include ProductController
end
class BarsController < ApplicationController
@model = "bar"
include ProductController
end
对于视图,ProductController已经定义了它们,只是为了在视图中使用通用匹配变量名。
<%= @obj.title %>
很干,不是吗?