如何在多个域上运行单个代码库?

时间:2016-07-11 00:53:02

标签: ruby-on-rails

我正在编写一个开源应用程序,它将由开发人员在他们自己的域上部署。我必须在很多地方引用域名,例如devise的默认邮件程序选项

指定应用程序域名的传统位置在哪里,如何在我的应用程序的其他部分引用它?

2 个答案:

答案 0 :(得分:1)

在Rails应用程序中,您可能需要访问与应用程序关联的域的几个区域。根据您需要的代码的特定区域,您有3种不同的情况:

  1. 在请求的上下文中运行的代码
  2. 在请求上下文之外运行的代码,但它由请求触发(或可能由请求触发)
  3. 在请求上下文之外运行的代码
  4. 举个例子:

    • 控制器在请求的上下文中运行
    • 模型方法在请求的上下文之外执行,但您可以在调用方法时传递上下文。但是,现在这始终适用(例如,如果通过CLI或后台作业执行相同的方法)
    • 调度程序运行的后台作业或任务完全在请求的上下文之外

    在请求的上下文中(直接或间接)操作的库易于处理。该方法通常是从请求本身检测特定主机名。

    虽然在大多数情况下这是实用的,但在其他情况下这有点复杂。一个值得注意的案例是ActiveMailer,它始终位于两个上下文之间。在大多数情况下,电子邮件是在HTTP请求的响应中触发的,但并非总是如此。此外,没有实用的方法将请求上下文从控制器传递到邮件程序,除非您明确地将request.env作为参数传递给您要发送的每封电子邮件。但这不是最实际的解决方案。

    对于简单需求,特别是ActionMailer,我创建了一个名为actionmailer_with_request的简单插件,它将请求的上下文存储在当前线程中,并使其可用于ActionMailer。我在这里提到它主要是为了完整性,但我是第一个承认它不是一个完整的解决方案也不是一个明确的解决方案。它也反对MVC架构。

    原因不是明确的解决方案,因为它并没有完全解决在您的电子邮件中提供域名的问题。事实上,如果邮件程序是由后台作业或cron作业触发的,那么您仍然没有请求上下文,因此主机名不会出现。同样,该问题仍适用于需要访问当前主机名的ActionMailer之外的所有系统。它可能是另一个邮件进程,或任何后台/外部进程。

    此时,仅仅依赖请求的上下文是不够的。实际上,您可能必须将信息存储在某处。

    您可以有几种不同的可能性。没有单一的推荐解决方案。一些替代方案是:

    • Rails配置对象,例如Rails.application.config.hostname = xxxx
    • 配置系统
    • Rails应用程序或环境中的常量

    在我们的例子中,我们在lib内有一个名称空间,我们存储了所有与应用程序相关的东西。我们也大量使用环境变量。

    因此,假设您的应用程序被称为Something(因此config/application中有module Something),我们就在lib/something.rb

    module Something
      def default_hostname
        ENV['SITE_HOST']
      end
    
      def default_protocol
        ENV['SITE_PROTOCOL']
      end
    end
    

    这些是方便的包装器,不直接公开环境变量。此外,它允许我们在配置变量,env或我们需要的任何东西之间进行交换,而无需修改代码的任何其他地方。

    然后,在config/environments/production.rb中,您需要更新邮件程序设置:

      config.action_mailer.default_url_options = { host: Something.default_hostname, protocol: Something.default_protocol }
    

    如果您希望将设置应用于所有上下文,您还可以决定在config/application.rb中对其进行配置。

    无论您何时需要访问请求上下文之外的主机名,都可以使用

    Something.default_hostname
    

    通过方法的便利性是你也可以设置默认值。

    module Something
      def default_hostname
        ENV['SITE_HOST'] || "example.com"
      end
    end
    

    也许是警告

    module Something
      def default_hostname
        ENV['SITE_HOST'] || begin
          warn("Please set SITE_HOST to configure your site URL")
          "example.com"
        end
      end
    end
    

答案 1 :(得分:-1)

如果您愿意,可以在Redis实例中进行设置:

https://github.com/redis/redis-rb

初始设置后

redis.set("mysite_url", "www.foo.com")
# => "OK"

然后在任何需要的地方拨打电话:

redis.get("mysite_url")
# => "www.foo.com"

如果需要,您可以从表单中进行设置,如果您需要从admin进行更改,则非常有用:

redis.set("mysite_url", params[:settings][:site_url])
# => "OK"