我想在Rails中使用全局对象时如何避免使用常量?

时间:2019-07-08 17:46:39

标签: ruby-on-rails ruby

我想将S3文件存储添加到我的rails 5应用程序中。由于我使用的是heroku,因此我使用了它们的tutorial,它表示只是在S3_BUCKET中创建一个名为config/initializers/aws.rb的常量,您可以在任何地方使用该常量。

heroku代码如下所示:

#config/initializers/aws.rb

S3_BUCKET = Aws::S3::Resource.new.bucket(ENV['S3_BUCKET'])

问题是我必须重写此常量才能使规范正常工作。

我有这个替代解决方案(很遗憾,它无法正常工作):

#lib/aws_helpers/s3.rb

module AWSHelpers
  module S3
    class << self
      attr_accessor :configuration

      def configure
        self.configuration ||= Configuration.new
        yield(configuration)
      end

      def bucket
        @bucket ||= Aws::S3::Resource.new.bucket(configuration.s3_bucket)
      end
    end

    class Configuration
      attr_accessor :s3_bucket, :aws_access_key_id, :aws_secret_access_key_id
    end
  end
end
#config/initializers/aws.rb

AWSHelpers::S3.configure do |config|
  config.s3_bucket = ENV['S3_BUCKET']
  config.aws_access_key_id = ENV['AWS_ACCESS_KEY_ID']
  config.aws_secret_access_key_id = ENV['AWS_SECRET_ACCESS_KEY']
end

我想要在控制器中执行的操作是:

AWSHelpers::S3.bucket.object(a_key)

不幸的是,这失败了,并告诉我bucket方法无法返回任何内容,因为配置为nil。

我所知道的:

  1. aws初始化程序被执行,当我通过所有方法添加puts时,通过rails s服务器启动服务器时,我可以看到正确的输出
  2. 控制器知道服务模块,或者甚至不了解bucket方法
  3. 当我将config/initializers/aws.rb的内容转储到控制器中时,代码有效

我真的很想知道为什么上面的代码不起作用。似乎正确设置了所有内容,然后突然想在控制器中使用它,就好像我从未打电话过configure一样。

我也欢迎其他有关如何执行此操作的建议。只能使用常量不是一种选择,因为必须更改常量才能使规范起作用。

2 个答案:

答案 0 :(得分:0)

此代码可能看起来很奇怪,但实际上正是您在这种情况下想要的代码。请记住,这种情况有点不规则,它是用于配置一个具有外部API依赖关系和相关密钥的插件,必须在其余代码工作之前对其进行填充。

从实现的角度来看这很丑陋,但是从可用性的角度来看,这很好。您可以按照初始化程序中所示执行AWSHelpers::S3.configure do |config|。所有这些代码都是为了使这些语义正常工作。

答案 1 :(得分:0)

这是一个便宜的把戏,但是它有用。

config/application.rb中:

module YourApp
  class Application < Rails::Application

    def s3_bucket
      @s3_bucket ||= begin
        # your stuff
      end 
    end 
  end
end 

Rails.application.s3_bucket.object(a_key)