2010-10-20 46 views
1

我有一個模型,它看起來是這樣的:Rails:將模型添加到模型以基於current_user執行檢查?

class Comment < ActiveRecord::Base 
    ... 
    #allow editing comment if it is moderated and the user passed-in 
    #is the one that owns the comment 
    def can_edit?(user) 
    moderated? and user.Type == User and user.id == self.user_id 
    end 
    ... 
end 

並在View的電話:

<%= link_to 'Show Comment', @comment if @comment.can_show?(current_user) %> 

我需要寫在許多不同的車型很多這樣的方法 - 排序驗證檢查來看看是否允許current_user 在模型上做些什麼。

但它感覺很累贅 - 特別是需要檢查傳入的user確實是User類型的對象。

什麼是乾淨的,最好的做法,做這種事情?我在正確的軌道上嗎? (即我應該加入這種方法的模型或其他地方)

注意

我使用範圍的查詢來獲得的評論和其他車型,但在某些情況下,我不能範圍查詢所以我必須使用can_xxxx?方法

Ps。我在做什麼被認爲是「胖胖的模特」?

回答

1

創建一個module包含所有需要授權的類的授權方法和include模塊。

將名爲authorization.rb的文件添加到app/models目錄。

module Authorization 

    def can_edit?(user) 
    moderated? and user.is_a?(User) and user.id == self.user_id 
    end 

    def self.included(base) 
    base.send(:extend, ClassMethods) 
    end 

    module ClassMethods 
    # add your class methods here. 
    end 
end 

一個名爲authorization.rb文件添加到config/initializers目錄。現在

%w(
Comment 
Post 
).each do |klass| 
    klass.constantize.include(Authorization) 
end 

CommentPost車型將擁有所有的授權方法。

其他方法是使用您當前的named_scope。

class Post 
    named_scope :accessible, lambda { |user| 
    { 
     :conditions => { :user_id => user.id, :moderated => true} 
    } 
    } 
end 

Post控制器動作

class PostsController 

    def index 
    @posts = Post.acessible(current_user) 
    # process data 
    end 

    def show 
    # throws record not found when the record is not accessible. 
    @post = Post.acessible(current_user).find(params[:id]) 
    # process data 
    end 

end 

我喜歡這種方法,因爲它使用相同的邏輯用於訪問對象的數組或一個單獨的對象。

您可以將named_scope添加到模塊,以避免重複定義:

module Authorization 
    def self.included(base) 
    base.named_scope :accessible, lambda { |user| 
     { 
     :conditions => { :user_id => user.id, :moderated => true} 
     } 
    } 
    end 

    module ClassMethods 
    # add your class methods here. 
    end 
end 

確保包括在模塊中所需的類正如前面建議。

+0

感謝*很多*。這種方法感覺更清潔。我想現在對於你的技術有很多深入的理解! – Zabba 2010-10-21 15:34:23

1

我不認爲你在做什麼是必然的錯誤。我看到三種簡化方法:

1)跟蹤self.user以及self.user_id。然後,您可以說:

def can_show?(user) 
    moderated ? and user == self.user 
end 

請注意,這可能會增加DB查找時間和/或內存佔用量的開銷。

2)使用#is_a?爲了檢查祖先,而不是剛下課的平等:

def can_show?(user) 
    moderated ? and user.is_a?(User) and user.id == self.user_id 
end 

3)如果傳遞一個非用戶是錯誤的,你可能想提高一個錯誤,當發生這種情況:

def can_show?(user) 
    raise "expected User, not #{ user.class.to_s }" unless user.is_a?(User) 
    moderated ? and user.id == self.user_id 
end 

至於Q2,我沒有聽說過「胖模特」的術語。它在任何地方被引用?

+0

我在網上看了一些最佳實踐提到「胖模型和瘦控制器」 – Zabba 2010-10-21 00:09:41

+0

我如何跟蹤評論模型中的用戶?它確實有一個user_id字段。 – Zabba 2010-10-21 00:14:39

1

重新:脂肪模型和瘦控制器

這是在控制器邏輯推到模型中而不是它(或更糟的是,視圖)的想法。

一大好處是幫助測試;也是在模型中放置更多邏輯的重點,而不是控制器。請記住,讓控制器適用於多個模型並不罕見。

將邏輯放入模型而不是控制器通常意味着業務規則正在被烘焙到模型中 - 這正是它們所屬的地方。

一個可能的缺點是控制器可用的任何信息在模型中不可用需要顯式傳遞到模型的方法或使用模型的實例變量「設置」。

您需要將當前用戶傳入模型的示例說明了此問題。

總的來說,我和其他許多人都發現,胖胖的模特往往比沒有更好。