2010-08-25 62 views
10

我在我的Rails應用程序中有一個私有方法來連接到Amazon S3,執行傳遞的代碼塊,然後關閉與S3的連接。它看起來是這樣的;如何使我的控制器和模型在Rails中都可用?

def S3 
    AWS::S3::Base.establish_connection!(
    :access_key_id  => 'Not telling', 
    :secret_access_key => 'Really not telling' 
) 
    data = yield 
    AWS::S3::Base.disconnect 
    data 
end 

它被這樣調用(作爲例子);

send_data(S3 {AWS::S3::S3Object.value("#{@upload_file.name}",'bucket')}, :filename => @upload_file.name) 

我調用了一些在我的控制器和模型方法此方法,以便把它包含在兩個類的私有方法。這工作正常,我很高興,但它不是很乾。

如何讓我的模型和控制器都可以訪問此方法,但只有代碼出現一次?這更像是一個Ruby問題,而不是一個Rails問題,它反映了我對OOP的新鮮感。我猜測一個模塊或混合模式就是答案,但我到目前爲止還沒有真正使用過這兩種模塊,並且需要一些手動操作。

謝謝。

回答

8

模塊用於ruby中的3種不同的東西。首先是命名空間。在模塊內部具有類或常量定義不會與該模塊之外的類或常量相沖突。像這樣的東西

class Product 
    def foo 
    puts 'first' 
    end 
end 

module Affiliate 
    class Product 
    puts 'second' 
    end 
end 

p = Product.new 
p.foo # => 'first' 

p = Affiliate::Product.new 
p.foo # => 'second' 

模塊的第二次使用是作爲一個地方來粘貼方法,其他地方並沒有真正的地方。你也可以在類內部做到這一點,但是使用模塊化的方式告訴人們閱讀代碼並不意味着實例化。像這樣的東西

module Foo 
    def self.bar 
    puts 'hi' 
    end 
end 

Foo.bar #=> 'hi' 

最後(也是最容易混淆的)是模塊可以包含到其他類中。以這種方式使用它們也被稱爲mixin,因爲您正在將所有方法「混合」到您所包含的任何方法中。

module Foo 
    def bar 
    puts 'hi' 
    end 
end 

class Baz 
    include Foo 
end 

b = Baz.new 
b.bar #=> 'hi' 

Mixins實際上是一個更復雜的話題,然後我在這裏覆蓋,但更深入可能會令人困惑。

對我而言,S3似乎真的屬於控制器,因爲控制器通常是處理傳入和傳出連接的東西。如果是這樣的話,我只需要在應用程序控制器上有一個受保護的方法,因爲所有其他控制器都可以訪問它,但仍然是私有的。

如果你確實有一個很好的理由在模型中,我會去一個混合。像

module AwsUtils 
private 
    def S3 
    AWS::S3::Base.establish_connection!\ 
     :access_key_id  => 'Not telling', 
     :secret_access_key => 'Really not telling' 

    data = yield 
    AWS::S3::Base.disconnect 
    data 
    end 
end 

東西,如果你把在lib/aws_utils.rb,你應該能夠在你的控制器和模型都將include AwsUtils使用它。 Rails知道要在lib中尋找類和模塊,但只有當名稱匹配時(在大的情況下)。我稱之爲AwsUtils,因爲我知道當rails看到(aws_utils.rb)時會看到什麼,並且說實話,我不知道S3Utils會需要什麼;-)

隨時可以索取更多信息如果我不清楚的東西。模塊往往是紅寶石中的一種,雖然令人驚歎,但對於新手來說卻是徹頭徹尾的困惑。

+0

美麗的謝謝。我同意這屬於控制器,但是我之前寫了原始代碼,然後才真正知道自己在做什麼。模型中有很多東西不應該存在,但我寧願不要現在就重寫它。你的技術已經很好地工作了,我已經能夠使用它將S3方法包含在另一個控制器中,所以它是值得的。我對模塊和mixin的理解仍然不完美(他們混淆 - 我同意),但這對我來說幫助很大。 – brad 2010-08-29 11:29:13

3

您的預感是正確的:您可以將模塊放在lib目錄中。在 爲了使這些方法提供給您的模型,只是它包含 有:

class Model < ActiveRecord::Base 
    include MyModule 
end 

所包含的模塊的實例方法會成爲您的類實例的方法。 (這被稱爲mixin)

module MyModule 
    def S3 
    #... 
    end 
end 
+0

1)你_can't_實例化模塊。 2)如果你包含一個模塊,它的所有實例方法都會成爲你的類的實例方法,所以要麼將它們放在單例類中,要麼包含它們,不要同時執行 – 2010-08-25 01:18:36

+0

你是對的......修正了。 – 2010-08-25 01:53:35

1

你可以寫一個模塊:

module MyModule 
    def self.S3(args*) 
    AWS::S3::Base.establish_connection!(
     :access_key_id  => 'Not telling', 
     :secret_access_key => 'Really not telling' 
    ) 
    data = yield 
    AWS::S3::Base.disconnect 
    data 
    end 
end 

,然後把它在你的控制器或模型

MyModule.S3(PARAMS *)

相關問題