Ruby on rails 如何使Rails中的控制器和模型都可以使用方法?

Ruby on rails 如何使Rails中的控制器和模型都可以使用方法?,ruby-on-rails,ruby,oop,Ruby On Rails,Ruby,Oop,我在Rails应用程序中有一个私有方法,可以连接到AmazonS3,执行传递的代码块,然后关闭到S3的连接。看起来是这样 def S3 AWS::S3::Base.establish_connection!( :access_key_id => 'Not telling', :secret_access_key => 'Really not telling' ) data = yield AWS::S3::Base.disconnect d

我在Rails应用程序中有一个私有方法,可以连接到AmazonS3,执行传递的代码块,然后关闭到S3的连接。看起来是这样

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
就这样叫(举例),

在我的控制器和模型中,我以多种方式调用此方法,因此将其作为私有方法包含在这两个类中。这个很好用,我很满意,但不是很干

我如何使我的模型和控制器都可以访问此方法,但代码只显示一次?这更像是一个Ruby问题而不是Rails问题,反映了我对OOP的新认识。我猜一个模块或一个混合是答案,但我还没有真正使用这两个到现在为止,需要一点手握住


谢谢。

你的直觉是正确的:你可以在lib目录中放置一个模块。在里面 为了使这些方法可用于您的模型,只需将其包括在内 与:


模块在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'
模块的第二个用途是作为一个粘贴方法的地方,而这些方法在其他任何地方都没有真正的位置。您也可以在类内执行此操作,但使用模块会告诉阅读代码的人它不应该被实例化。像这样的

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'
实际上,mixin是一个比我在这里讨论的更为复杂的主题,但深入一点可能会让人困惑

现在,对我来说,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需要什么;-)


如果我对某些事情不清楚,请随时询问更多信息。模块往往是ruby中令人惊奇的东西之一,但对新手来说却完全令人困惑

您可以将模块编写为:

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
然后在控制器或模型中调用它作为


S3(参数*)

1)不能实例化模块。2) 如果您包括一个模块,那么它的所有实例方法都将成为类上的实例方法,所以要么将它们放在singleton类上,要么将它们包括在内,不要同时做这两件事,谢谢。我同意这属于控制器,但在我真正知道自己在做什么之前,我已经编写了原始代码。模型中有很多不应该存在的东西,但我现在不想重写它。您的技术工作得很好,我也能够使用它在另一个控制器中包含S3方法,所以这是值得的。我对模块和mixin的理解仍然不完善(它们让人困惑——我同意),但这对我很有帮助。
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