2

假设有一个产品控制器,您想要一个索引(列出产品)操作。简单的。现在假设您有一个管理员并在您的项目中存储部件。两者都需要列出产品,但方式略有不同(例如,商店不应该有这个编辑产品链接)。他们还使用不同的布局。

到目前为止,我的想法是在不同的命名空间下拥有两个产品控制器 -app/controllers/admin/products_controller.rb并且app/controllers/store/products_controller.rb- 每个都有自己的视图和布局。但我怀疑这可能会导致 WET 代码。或者对其他控制器视图的引用(imo 破坏了模块化,因此应该避免)。

那么,实际的问题是:是否有更干燥(或实际上正确)的方式来实现上述目标?

我不确定标题是否真的反映了这个问题。但是,另一方面,如果是的话,我可能可以用谷歌搜索答案。

编辑 从 3.1 开始,Rails 支持模板继承。

4

4 回答 4

2

如果您在管理部分和商店部分之间显示产品的方式是不变的,除了管理链接(创建、编辑、销毁),那么我认为为您的产品创建一个部分是最简单的。我假设您有办法判断用户是否是管理员(为了简单起见,我将只使用 admin? 下面)。在你的局部你做这样的事情......

<div class="product">
    <div class="productheader">
        <%=h product.title %>
    </div>
    <div class="productdescription>
        <%=h product.description %>
    </div>
    <% if admin? %>
    <div class="productadmin">
        <%= link_to "Delete", destroy_product_url %>
        <%= link_to "Edit", edit_product_url %>
    </div>
    <% end %>
</div>

请务必将此部分命名为 _product.html.erb(下划线告诉 rails 该模板是部分模板)。在应用程序的 app/views 目录中创建一个名为 shared 的文件夹,并将部分内容存储在那里。

要在其他视图中渲染此部分,只需调用 render 方法并传递部分参数。

单品:

<%= render(:partial => "shared/product", :object => @a_product) %>

多种产品:

<%= render(:partial => "shared/product", :collection => @products) %>

通过添加布局参数,可以将布局应用于局部。部分布局必须以下划线为前缀,但存储在与控制器关联的 app/views 目录中。

<%= render(:partial => "shared/product", :object => @a_product, :layout => "somelayout" %>
于 2009-04-26T12:30:54.110 回答
1

我采用的方法是为产品创建一个控制器,并在其中添加代码以检测用户扮演的角色,并根据该角色有条件地设置视图数据。这包括实际模型数据和仅由视图用于确定要显示界面的哪些位的数据。然后,视图本身包含少量代码,这些代码能够作用于基于角色的数据并仅呈现与特定角色相关的那些位。有人可能会争辩说,这是将一些业务逻辑注入到视图中,或者将一些显示逻辑注入到控制器中——这些论点具有一定的有效性。但是,我发现它实际上更像是一种原则之间的平衡行为,我更喜欢价值 DRY 而不是 MVC 纯度。

于 2009-04-26T12:33:16.723 回答
0

您正在描述模型-视图-控制器模式,其中模型视图和控制器可以正交变化(或或多或少正交,取决于其实现方式)。

基本上,您有一个允许编辑的视图和一个不允许编辑的视图。同样,根据实现,可编辑视图可以从不可编辑视图派生。在任何一种情况下,控制器或一些更高级别的代码都会有条件地选择正确的视图。

于 2009-04-26T12:29:43.817 回答
0

如果只有某种视图继承......这样就可以继承控制器而无需提供其所有视图。好在有这个补丁。糟糕的是,它在很长一段时间内都无法进入核心。

将它应用到我的 rails 2.2 后,我设法对原始问题得到了以下答案。

子类化控制器

ProductController 有幸拥有这对双胞胎:

class Products::AdminController < ProductsController
  layout 'admin'
  before_filter :authenticate
end

class Products::StoreController < ProductsController
  layout 'store'
  before_filter :find_cart
end

这本身看起来很不错,因为它们中的每一个都带有自己的初始化部分。

改变路线

  map.resources :products, :controller => 'products/admin', :path_prefix => 'admin',
    :name_prefix => 'admin_'
  map.resources :products, :controller => 'products/store', :path_prefix => 'store',
    :only => [:show, :index], :name_prefix => 'store_'

不是一条容易的路线,defo。但是,嘿,在这一点之后,一切都可以使用 ProductController 视图和部分工作(假设您修复了路径助手)。

共享视图更改

每个子类控制器都有自己的 index.html.erb 版本。其他所有内容都在基类中共享。

谈论共享模板中的路径助手。曾经是什么

<% form_for @product ... %>

变成

<% form_for [controller_name, @product] ... %>

并且像

<%= link_to products_path %>

变成

<%= link_to send("#{controller_name}_products_path") %>

我不知道这是否值得,但这是一种方式。任何人都知道为什么如果计划很快将这个补丁包含在 Rails 中?

于 2009-05-08T22:46:25.410 回答