2009-04-26 67 views
2

假設有一個產品控制器需要索引(列出產品)的操作。簡單。現在說你有一個管理員和零件存儲在你的項目中。兩者都需要列出產品,但方式稍有不同(商店不應該有此編輯產品鏈接)。他們也使用不同的佈局。有條件查看/佈局

到目前爲止,我的想法是有兩個產品控制器在不同的名稱空間下 - app/controllers/admin/products_controller.rbapp/controllers/store/products_controller.rb - 每個控制器都有自己的視圖和佈局。但我懷疑這可能會導致WET代碼。或者對其他控制器視圖的引用(其中imo打破模塊化,因此應該避免)。

所以,真正的問題是:還有更多的DRY(或實際上是適當的)方式來實現上述?

我不確定標題實際上是否反映了這個問題。但是,另一方面,如果是這樣,我可以谷歌答案。

編輯 從3.1開始,Rails支持模板繼承。

回答

0

您正在描述模型視圖控制器模式,其中模型視圖和控制器可以正交(或多或少正交,取決於它的實現方式)變化。

非常基本上,你有一個視圖允許編輯,另一個不允許編輯。同樣,取決於實施方式,可編輯視圖可以從不可編輯視圖派生出。在任何一種情況下,控制器或某些更高級別的代碼都會有條件地選擇正確的視圖。

+0

即使在非編輯視圖中,在視圖中也需要一些智能來確定是否顯示編輯鏈接 - 除非您只是希望它對非管理員失敗。我寧願它不可見。因此,除非您想爲管理員/普通用戶完全分開視圖,否則必須在控制器和視圖之間引入更多的耦合。 – tvanfosson 2009-04-26 12:36:35

2

如果您在管理部分和商店部分之間顯示產品的方式除了管理鏈接(創建,編輯,銷燬)之外是恆定的,那麼我認爲最容易爲您的產品創建一個部分。我假設你有一種方式來判斷用戶是否是管理員(我將在下面簡單地使用管理員?)。裏面的部分,你做這樣的事......

<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(下劃線告訴軌,模板是部分)。在應用程序的app/views目錄中創建一個名爲shared的文件夾,並在其中存儲該部分。

要在您的其他視圖中渲染此部分,只需調用render方法並傳遞partial參數即可。

單品:

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

多種產品:

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

佈局可以通過添加布局參數被施加到分音。部分佈局必須以下劃線作爲前綴,但存儲在與控制器關聯的app/views目錄中。

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

的做法,我採取的是有產品單一的控制器和代碼添加到它來檢測用戶的戲劇和有條件地設置視圖數據基於該角色的作用。這包括實際模型數據和僅由視圖使用的數據,以確定要顯示的接口的哪些位。然後,視圖本身包含一小部分代碼,這些代碼能夠處理基於角色的數據,並只顯示與特定角色相關的位。有人可能會爭辯說,這是在視圖中注入一些小的業務邏輯,或者在控制器中注入一些顯示邏輯 - 而這些參數具有一定的有效性。然而,我發現它實際上更像是原則之間的平衡行爲,我更喜歡價值DRY而不是MVC純度。

0

如果只有某種視圖繼承...所以,可以不需要提供所有視圖的子類控制器。好的是,這是patch。糟糕的是,它無法在一段時間內達到核心水平。

將它應用到我的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_' 

不是一件容易的路線,傑福。但是,嘿,在這一點之後,所有的東西都能正常工作(假設你使用了固定路徑助手)並且使用了ProductController視圖和partials。

共享視圖改變

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

說說共享模板中的路徑助手。曾經被認爲是

<% form_for @product ... %> 

成爲

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

和變薄像

<%= link_to products_path %> 

轉成

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

我不知道這是否是一切都是值得的,但那是一種方式。任何人都知道爲什麼如果有計劃很快將這個補丁包含在rails中?