2

我正在编写一个库存管理 Rails 应用程序。我有class Product < ActiveRecord::Base和。Foo 和 Bar 的行为略有不同,但使用单表继承对它们来说非常有用。class Foo < Productclass Bar < Product

问题在于控制器和视图。目前我将它们完全分开,这可行,但包含大量重复代码。一个可以通过复制两个目录并将@foo,和替换为,@foos和来从另一个生成。当我添加新功能时,添加两次会很烦人。而且,当然,不干也不是 Rails 方式。Foo@bar@barsBar

那么这里的正确方法是什么?对于控制器......我应该制作一个ProductsController然后只使用元编程魔法来代替FooBar吗?还是使用继承?对于视图,我是否应该只有产品视图,但使用巧妙的路由使其看起来像我有单独的(和 RESTful)/foos/bars路径?

谢谢。

4

3 回答 3

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为所有常见的视图部分创建一个目录,这是另一种非常常见的方法,允许您以最小的麻烦完全 RESTful 控制 URL。如果您的对象也有类似的方法,那么视图不需要知道它正在处理什么类。

在上面的控制器中,访问 foos/new 的用户将启动对 new_resource 的调用,该调用将构建一个新的 Foo 实例并将其作为@resource 返回到页面。

#View:
<%= render 'shared/product_details', :locals => {:product => @resource} %>
于 2013-05-28T15:32:24.087 回答
0

如果你有完全相同的控制器方法和视图,你可以把它移到产品中——这样,你就会有Product,@product@products. 既然是STI, 和 上没有 ID 重复FooBar所以成员路由也可以工作。此外,由于模型不同,鸭子类型将负责为每个模型调用正确的方法。

然后,您可以将两个子模型中未重复的所有内容移动到特定的控制器。

于 2013-05-28T15:36:17.123 回答
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 %>

很干,不是吗?

于 2013-05-28T18:21:00.980 回答