2012-03-13 74 views
1

我有一個應用程序,可從特定國家/地區檢索用戶列表。Rails:如何以及在哪裏添加此方法

我這樣做的UsersController

@fromcanada = User.find(:all, :conditions => { :country => 'canada' }) 

,然後把它變成一個範圍在User模型

scope :canada, where(:country => 'Canada').order('created_at DESC') 

,但我也希望能夠檢索一個素不相識的人或多個來自國家的人。我發現這種方法應該是從數據庫中檢索隨機用戶的有效方法。

module ActiveRecord 
    class Base 
    def self.random 
     if (c = count) != 0 
     find(:first, :offset =>rand(c)) 
     end 
    end 
    end 
end 

但是,我有幾個關於如何添加它以及語法如何工作的問題。

  1. 我會在哪裏放置該代碼?直接在User模型中?

  2. 語法:所以我不使用我不明白的代碼,你能解釋語法是如何工作的嗎?我沒有得到(c = count)。什麼是count計數? rand(c)在做什麼?它是否找到第一個從偏移量開始的?如果rand是一個昂貴的方法(因此需要創建一個更高效的random方法),爲什麼在這個新的更高效的random方法中使用昂貴的「rand」?

  3. 我該如何在我的find方法UsersController上添加對random的呼叫?如何將它添加到模型中的範圍?

  4. 建立在問題3上,有沒有辦法讓兩個或三個隨機用戶?

回答

0

我不會把這個(或其他任何東西)修補到ActiveRecord中,把它放到你的用戶中會更有意義。

count正在統計表格中有多少個元素,並將該數字存儲在c中。然後rand(c)給出在區間[0,c)(即0 <= rand(c) < c)中的隨機整數。 :offset按照您認爲的方式工作。

rand是不是非常昂貴,但在數據庫中做order by random()可以非常昂貴。您正在查看的random方法只是從數據庫獲取隨機記錄/對象的一種便捷方式。

它添加到您自己的用戶會是這個樣子:

def self.random 
    n = scoped.count 
    scoped.offset(rand(n)).first 
end 

這將讓您鏈random一堆範圍後:

u = User.canadians_eh.some_other_scope.random 

random結果將是一個用戶,所以你的鏈接將停止在那裏。

如果您想要多個用戶,您希望多次撥打random,直至獲得您想要的用戶數量。你可以試試這個:

def self.random 
    n = scoped.count 
    scoped.offset(rand(n)) 
end 

us = User.canadians_eh.random.limit(3) 

獲得三個隨機的用戶,但用戶會在數據庫中結束了與其他範圍後任何順序聚集在一起,而這可能不是你以後。如果您想你們三個會是更好的東西掉這樣的:

# In User... 
def self.random 
    n = scoped.count 
    scoped.offset(rand(n)).first 
end 

# Somewhere else... 
scopes = User.canadians_eh.some_other_scope 
users = 3.times.each_with_object([]) do |_, users| 
    users << scopes.random 
    scopes = scopes.where('id != :latest', :latest => users.last.id) 
end 

你只抓住一個隨機的用戶,更新您的作用域鏈排斥他們,並重復,直到你完成。當然,你會首先確定你有三個用戶。

您可能希望將訂單移出canada範圍:一個範圍,一個任務。

0
  1. 該代碼注入一個新的方法到ActiveRecord :: Base。我會把它放在lib/ext/activerecord/base.rb中。但是你可以把它放在任何你想要的地方。

  2. count是一種自我調用的方法。 self會是一些從ActiveRecord :: Base繼承的類,例如。用戶。 User.count返回用戶記錄的數量(sql:SELECT count(*) from users;)。蘭德是一個紅寶石stdlib方法Kernel#randrand(c)返回範圍0...c中的一個隨機整數,c先前通過調用#count進行計算。蘭特並不昂貴。

  3. 您不會隨意使用find查找,User#random是查找,它會從所有用戶記錄中返回一個隨機記錄。在你的控制器中,你說User.random,它返回一個隨機記錄(如果沒有用戶記錄,則返回零)。

  4. 修改AR ::基地::隨機方法,像這樣:

    module ActiveRecord 
        class Base 
        def self.random(how_many = 1) 
         if (c = count) != 0 
         res = (0..how_many).inject([]) do |m,i| 
          m << find(:first, :offset =>rand(c)) 
         end 
         how_many == 1 ? res.first : res 
         end 
        end 
        end 
    end 
    
    User.random(3) # => [<User Rand1>,<User Rand2>,<User Rand3>] 
    
相關問題