2016-04-26 56 views
1

我想猴子補丁ActiveRecord :: FinderMethods爲了使用我的模型哈希ID。因此,例如User.find(1)變爲User.find(「FEW」)。可悲的是我的覆蓋方法沒有被調用。任何想法如何覆蓋find_one方法?Monkeypatch ActiveRecord :: FinderMethods

module ActiveRecord 
    module FinderMethods 
    alias_method :orig_find_one, :find_one 
    def find_one(id) 
     if id.is_a?(String) 
     orig_find_one decrypt_id(id) 
     else 
     orig_find_one(id) 
     end 
    end 
    end 
end 
+3

這可能是一個非常糟糕的主意,它可能會破壞內部。爲什麼不編寫自己的替代方法並在控制器中使用它?而不是'find_hashed_id'。 – tadman

+0

感謝您的輸入,我將使用find_hashed_id :) – krnflake

回答

1

以下是討論通過重寫User.primary_key方法怎麼樣真正做到你想要什麼的文章:

class User 
    self.primary_key = 'hashed_id' 
end 

這將允許你打電話User.find,並將它傳遞了「hashed_id」:

http://ruby-journal.com/how-to-override-default-primary-key-id-in-rails/

所以,這是可能的。

這就是說,我會建議不要那樣做,而應該使用類似User.find_by_hashed_id的東西。唯一的區別是當找不到結果而不是拋出ActiveRecord::RecordNotFound異常時,此方法將返回nil。你可以在你的控制器手動拋出這樣的:

def show 
    @user = User.find_by_hashed_id(hashed_id) 
    raise ActiveRecord::RecordNotFound.new if @user.nil? 
    ... continue processing ... 
end 

最後一個別注使它更容易些你 - 的Rails也有一個方法,你可以在你的模型,to_param覆蓋,告訴它使用什麼屬性生成路線時。默認情況下,它使用id,但你可能想要使用hashed_id。現在

class User 
    def to_param 
    self.hashed_id 
    end 
end 

,在你的控制器,params[:id]將包含hashed_id,而不是ID。

def show 
    @user = User.find_by_hashed_id(params[:id]) 
    raise ActiveRecord::RecordNotFound.new if @user.nil? 
    ... continue processing ... 
end 
+0

對於像這樣的情況,如果這種類型的ID隱藏是普遍存在的,我有時會把'to_param'的對立面稱爲'from_param'的類級別方法。這是一個很好的,徹底的答案,但值得一提的是,「if @ user.nil?」被過度殺死。首先,'@ user'永遠不會是'false',所以'除非@ user'足夠,但如果你使用'find_by_hashed_id!',它會自動爲你提出這個錯誤。 – tadman

+0

我不知道那些額外的查找方法支持「!」,這很好理解,謝謝。是的,「無?」是我還沒有動搖的習慣! – GoGoCarl

+1

像'save'那樣會返回一個錯誤,'save!'會拋出一個異常,通常會有一個拋出任何給定的ActiveRecord方法的異常。起初對Ruby有點不安的事情之一就是'nil'和'false'在邏輯上是錯誤的值,'0'和'「」'仍然是真實的。只要你擁抱,你的代碼可以簡單得多。其他語言需要大量工作來區分'0'和false。在Rails中,如果你關心對象有多少實體,你確實有'.present?'。 – tadman

1

我同意你這樣做時應該小心,但這是可能的。

如果你有一個方法decode_id,其轉換散列ID回到原來的ID,然後下面的工作:

在User.rb

# Extend AR find method to allow finding records by an encoded string id: 
def self.find(*ids) 
    return super if ids.length > 1 

    # Note the short-circuiting || to fall-back to default behavior 
    find_by(id: decode_id(ids[0])) || super 
end 

只要確保decode_id回報如果它傳遞了一個無效散列,則爲零。這樣,您就可以通過散列ID和標準ID找到,所以如果你有一個用戶ID爲12345,然後執行以下操作:

User.find(12345) 
User.find("12345") 
User.find(encode_id(12345)) 

應該都返回相同的用戶。