2011-08-10 41 views
1

我試圖將我的一些查詢從控制器移動到模型,但我有麻煩,使得它像我想要的那樣乾淨。這裏是我正在使用的機型:Rails:訪問屬於類方法屬於關係的實例屬性

class Post < ActiveRecord::Base 
    belongs_to :account 

    def self.recent_posts(account=nil) 
     if account.nil? || account.tags.nil? 
      results = where(:published => true).order('created_at DESC').limit(5) 
     else 
      results = tagged_with(account.tags).where(:published => true).order('created_at DESC').limit(5) 
     end 
    end 
end 

class Account < ActiveRecord::Base 
    has_many :posts 
end 

然後在我打電話像posts = account.posts.recent_posts(account)控制器。

但是,在我看來,應該有一些方法來訪問account.tags而不必將account實例傳遞給account.posts.recent_posts類方法。有沒有,還是我正在接近這個錯誤的方式?謝謝!

回答

0

類方法不知道特定的實例,除非你傳入一個參考。畢竟,它們完全不同。這很容易作出要求傳遞到類方法實例方法:

def recent_posts 
    self.class.recent_posts(self) 
end 

這可能看起來有點笨拙,但它是當你有一個需要一類級別的實用方法經常出現的模式一點範圍信息。

您可能還希望來表達你的測試,因爲這:

if (!account || !account.tags?) 
    # ... 
end 

一般來說,你不需要測試nil?明確,除非你是有關價值可能是false,一種罕見的情況下,在這樣的情況下這個。還有一種爲文本字段引入的方法,可以測試該值是否同時定義爲非空白account.tags?相當於account.tags.present?這是account.tags.blank?

+0

首先使用實例方法並調用類方法是有意義的。唯一的問題是我無法弄清楚如何在諸如'account.posts.instance_method'的控制器中調用實例方法。我猜這是因爲當時沒有「Post」模型的實例。 –

+0

您需要一次對一個或多個帖子進行操作。例如:'account.posts.collect(&:recent_posts).flatten'可以工作,但它可以變得更有效率。 – tadman

2

第一遍清理乾淨,將像

class Post < ActiveRecord::Base 
    belongs_to :account 

    scope :sane_defaults, where(:published => true).order('created_at DESC').limit(5) 
    scope :with_account, lambda {|account| 
     if account.try(:tags) 
     tagged_with(account.tags) 
     end 
    } 
end 

,然後打電話給逆Post.with_account(account).sane_defaults

這是令人沮喪的是tagged_with沒有發揮好與其他範圍。大多數範圍返回一個可以鏈接的活動關係對象,但顯然當傳遞nil或甚至是一個空數組時,tagged_with返回一個散列。這是不禮貌的,應該修復。

通常在Ruby中,不會檢查nil,因爲nil是falsey值,並且檢查對象的存在是否更短並評估truthy。
您也可以分配if表達式的結果。所以它會更idomatic說

results = if account && account.tags 
     tagged_with(account.tags).where(:published => true).order('created_at DESC').limit(5) 
    else 
     where(:published => true).order('created_at DESC').limit(5) 
    end 

有關於試法的爭論相當數量的,但如果你沒有它是否是好還是壞的做法的意見,直到你開發一個使用它。它可以讓你縮短

if account && account.tags 

if account.try(:tags) 

這將看到您的控制器方法的全部是有趣。