【问题标题】:In Sinatra(Ruby), how should I create global variables which are assigned values only once in the application lifetime?在 Sinatra(Ruby) 中,我应该如何创建在应用程序生命周期中只赋值一次的全局变量?
【发布时间】:2011-05-30 08:32:46
【问题描述】:

在 Sinatra 中,我无法创建在应用程序生命周期中只赋值一次的全局变量。我错过了什么吗?我的简化代码如下所示:

require 'rubygems' if RUBY_VERSION < "1.9"
require 'sinatra/base'

class WebApp < Sinatra::Base
  @a = 1

  before do
    @b = 2  
  end

  get '/' do
    puts @a, @b
    "#{@a}, #{@b}"
  end

end

WebApp.run!

这会导致

nil
2

在终端中,,2 在浏览器中。

如果我尝试将 @a = 1 放入 initialize 方法中,我会在 WebApp.run! 行中收到错误消息。

我觉得我错过了一些东西,因为如果我不能拥有全局变量,那么我如何在应用程序实例化期间加载大数据?

before do 似乎在每次有来自客户端的请求时都会被调用。

【问题讨论】:

  • @a 不起作用的原因是get 块在WebApp 类的实例的上下文中运行,而您在类的上下文中设置它。它就像任何实例变量一样。如果您将其更改为 @@a 它应该可以工作(但有更好的方法,请参阅下面的答案)。
  • 抱歉延迟回复。所以,你的意思是,每个http get 创建一个WebApp 的实例。这解释了很多。谢谢。

标签: ruby web-applications sinatra


【解决方案1】:
class WebApp < Sinatra::Base
  configure do
    set :my_config_property, 'hello world'
  end

  get '/' do
    "#{settings.my_config_property}"
  end
end

请注意,如果您使用 Shotgun 或其他在每个请求上重新加载代码的 Rack 运行器工具,则每次都会重新创建该值,并且看起来好像它不是只分配一次。在生产模式下运行以禁用重新加载,您会看到它仅在第一个请求时分配(例如,您可以使用 rackup --env production config.ru 执行此操作)。

【讨论】:

  • 这很有帮助。只是想补充一点,如果您想稍后更改设置,则需要使用常规分配,例如:def '/change'{ settings.my_config_property = 'goodbye world' }
  • 另外 - 如果你在 Heroku 之类的东西上运行,你的应用程序的每个实例都会有自己的任何全局副本,所以它们通常只能用作缓存。
  • @Fotios 我有点想动态更改设置,但对您编写的代码有点不清楚。你能详细说明一下吗?
  • +1 提示 Shotgun,只是无法弄清楚为什么我的配置变量会被覆盖,直到我来到这里并且一分钱都掉了 - 这当然正是 Shotgun 的工作原理!
  • 如何将全局变量值分配给控制器中的变量?设置全局变量后,我尝试打印值,它们工作并在控制台中显示值,但如何将它们分配给变量。我试过这个:“totalUnits = settings.totalUnits_”。 “totalUnits_”是我的全局变量。这会引发错误:未定义的局部变量或方法 `settings' for.....
【解决方案2】:

我遇到了类似的问题,我试图使用initialize 方法初始化实例变量@a,但每次都收到异常:

class MyApp < Sinatra::Application

    def initialize
        @a = 1
    end

    get '/' do
        puts @a
        'inside get'
    end
end

我最终决定研究 Sinatra 代码进行初始化:

# File 'lib/sinatra/base.rb', line 877

def initialize(app = nil)
  super()
  @app = app
  @template_cache = Tilt::Cache.new
  yield self if block_given?
end

看起来它做了一些必要的引导,我需要打电话给super()

    def initialize
        super()
        @a = 1
    end

这似乎解决了我的问题,一切都按预期工作。

【讨论】:

    【解决方案3】:

    另一种选择:

    helpers do
    
      def a
       a ||= 1
      end
    
    end
    

    【讨论】:

      【解决方案4】:

      您可以使用 OpenStruct。

      require 'rubygems'
      require 'sinatra'
      require 'ostruct'
      
      configure do
        Struct = OpenStruct.new(
          :foo => 'bar'
        )
      end
      
      get '/' do
        "#{Struct.foo}" # => bar
      end
      

      您甚至可以在视图和其他加载的文件中使用 Struct 类。

      【讨论】:

      • 来吧..你正在重新定义Struct
      猜你喜欢
      • 2015-01-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多