简体   繁体   English

如何在Rails中为我的控制器和模型提供方法?

[英]How do I make a method available to both my controller and model in Rails?

I have a private method in my Rails app to connect to Amazon S3, execute a passed block of code, then close the connection to S3. 我在我的Rails应用程序中有一个私有方法连接到Amazon S3,执行传递的代码块,然后关闭与S3的连接。 It looks like so; 看起来像这样;

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

It is called like this (as an example); 它被称为这样(作为一个例子);

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

I call this method in a number of ways in my controller and model so have it included in both classes as a private method. 我在我的控制器和模型中以多种方式调用此方法,因此将它作为私有方法包含在两个类中。 This works fine and I'm happy with it but it's not very DRY. 这很好用,我很高兴,但它不是很干。

How can I make this method accessible to both my model and controller but only have the code appear once? 如何让我的模型和控制器都可以访问此方法,但只能让代码出现一次? This is more of a Ruby question than a Rails question and reflects my newness to OOP. 这是一个Ruby问题而不是Rails问题,反映了我对OOP的新见解。 I'm guessing a module or a mix-in is the answer but I haven't really been using either of these up until now and need a little hand-holding. 我猜测一个模块或混合是答案,但我到目前为止还没有真正使用过这两个模块,需要一点手握。

Thanks. 谢谢。

Modules are used for 3 different things in ruby. 模块用于ruby中的3种不同的东西。 First is namespacing. 首先是命名空间。 Having class or constant definitions inside a module won't collide with classes or constants outside that module. 在模块内部具有类或常量定义不会与该模块之外的类或常量发生冲突。 Something like this 像这样的东西

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'

The second use for modules is as a place to stick methods that don't really have a place anywhere else. 模块的第二个用途是作为一个固定方法的地方,这些方法在其他任何地方都没有。 You can do this inside a class too, but using a module sort of tells people reading the code that it is not meant to be instanciated. 您也可以在类中执行此操作,但使用模块类型可以告诉读取代码的人员,这些代码并不是要实现的。 Something like this 像这样的东西

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

Foo.bar #=> 'hi'

Finally (and the most confusing) is that modules can be included into other classes. 最后(也是最令人困惑的)是模块可以包含在其他类中。 Using them this way is also referred to as a mixin, because you are "mixing in" all the methods into whatever you are including. 以这种方式使用它们也被称为mixin,因为您将所有方法“混合”到您所包含的任何内容中。

module Foo
  def bar
    puts 'hi'
  end
end

class Baz
  include Foo
end

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

Mixins are actually a way more complected topic then I am covering here, but going deeper would probably be confusing. Mixins实际上是一个比较复杂的主题,然后我在这里讨论,但更深入可能会令人困惑。

Now, to me, S3 seems to be something that really belongs in the controller, since controllers are usually the things dealing with incoming and outgoing connections. 现在,对我来说,S3似乎真的属于控制器,因为控制器通常是处理传入和传出连接的东西。 If that is the case, I would just have a protected method on application controller, since that will be accessible to all other controllers, but still be private. 如果是这种情况,我会在应用程序控制器上有一个受保护的方法,因为所有其他控制器都可以访问它,但仍然是私有的。

If you do have a good reason for it being in the model too, I would go for a mixin. 如果你确实有充分的理由将它放入模型中,我会选择mixin。 Something like 就像是

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

If you put that in lib/aws_utils.rb , you should be able to use it by adding include AwsUtils in both your controller and your model. 如果将其放在lib/aws_utils.rb ,则应该可以通过在控制器和模型中添加include AwsUtils来使用它。 Rails knows to look for classes and modules in lib, but only if the name matches (in wide case). Rails知道在lib中查找类和模块,但只有在名称匹配时(大例)。 I called it AwsUtils because I know what rails will look for when it sees that (aws_utils.rb), and to be honest, I have no idea what it will need for S3Utils ;-) 我把它称为AwsUtils,因为我知道当它看到(aws_utils.rb)时会找到什么轨道,说实话,我不知道S3Utils需要什么;-)

Feel free to ask for more info if I wasn't clear on something. 如果我不清楚某些事情,请随时询问更多信息。 Modules tend to be one of those things in ruby that while amazing, are downright baffling to newcomers. 模块往往是红宝石中的那些东西之一,虽然令人惊讶,但对于新手来说却是令人费解的。

Your hunch is correct: you can put a module in the lib directory. 你的预感是正确的:你可以将一个模块放在lib目录中。 In order to make these methods available to your models, simply include it with: 为了使这些方法适用于您的模型,只需将其包含在:

class Model < ActiveRecord::Base
  include MyModule
end

The included module's instance methods will become instance methods on your class. 包含的模块的实例方法将成为您的类的实例方法。 (This is known as a mixin) (这被称为mixin)

module MyModule
  def S3
    #...
  end
end

You can write a module as : 您可以将模块编写为:

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

and then call it in your controller or model as 然后在控制器或模型中将其称为

MyModule.S3(params*) MyModule.S3(PARAMS *)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何让工厂可以使用辅助方法? (导轨,Rspec) - How do I make a helper method available to factories? (Rails, Rspec) Rails:如何制作一个调用自定义控制器方法的按钮? - Rails: How do I make a button that calls a custom controller method? 如何使用Ajax向我的Rails控制器发出POST请求? - How do I make a POST request to my Rails controller with Ajax? rails:如何访问应用程序控制器中的方法? - rails: how do i access a method in my application controller? 如何在Rails 3.2的视图和控制器中使用下划线方法? - How to make underscore method available in view and controller in rails 3.2? Rails-模型中控制器中的辅助方法? - Rails - helper method in controller available in the model? 如何使lib模块方法在项目范围内可用,并且还特定于Ruby on Rails中的类? - How do I make a lib module method available project-wide and also specific to a class in Ruby on Rails? 什么时候需要为滑轨制作新的控制器/模型? - when do I need to make a new controller/model for rails? Ruby on Rails:如何在模型中创建初始化方法,还是应该在控制器中设置所有默认参数? - Ruby on Rails: how do I create an initializer method in the model or should I set all the default params in a controller? 如何在Rails3中将红宝石迭代移动到控制器/模型中 - How do I move my ruby iteration into my controller / model in Rails3
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM