2

在我的 Rails 应用程序中,我正在尝试创建一个预订表格,外部各方(parks)可以指向他们的客户为相应的公园进行预订。预订表格与带有子域书的 url/路由一起使用

https://book.myapp.com/en/parks/:park_id/park_availability

目标

我想myapp.com用 的网站替换我的域 ( ) park,这样我得到

https://book.parkapp.com/en/park_availability

不幸的是,我在创建公园时收到错误消息

NameError (uninitialized constant #<Class:0x0000563d7bf62250>::Heroku):

使用现有公园时

{park.website}'s server IP address could not be found.

概述尝试的方法

  1. Park有一个website专栏。在routes.rb我尝试设置约束并将它们应用于park_availability动作。
  2. 在保存公园后,Park我尝试在模型中将域 ( ) 添加到我的 Heroku 应用程序中。Park.website
  3. 在我的行动之前,Park controller我尝试找到, 。@parkpark_availability

代码

路线.rb

class CustomDomainConstraint
  # Implement the .matches? method and pass in the request object
  def self.matches? request
    matching_site?(request)
  end

  def self.matching_site? request
    # handle the case of the user's domain being either www. or a root domain with one query
    if request.subdomain == 'www'
      req = request.host[4..-1]
    else
      req = request.host
    end

    # first test if there exists a Site with a domain which matches the request,
    # if not, check the subdomain. If none are found, the the 'match' will not match anything
    Park.where(:website => req).any?
  end
end

Rails.application.routes.draw do
  resources :parks do
     match ':website/park_availability' =>  'parks#park_availability', on: :member, :constraints => CustomDomainConstraint, via: :all
end
end

公园.rb

class Park < ApplicationRecord
  after_save do |park|
  heroku_environments = %w(production staging)
  if park.website && (heroku_environments.include? Rails.env)
    added = false
    heroku = Heroku::API.new(api_key: ENV['HEROKU_API_KEY'])
    heroku.get_domains(ENV['APP_NAME']).data[:body].each do |domain|
      added = true if domain['domain'] == park.website
    end

    unless added
      heroku.post_domain(ENV['APP_NAME'], park.website)
      heroku.post_domain(ENV['APP_NAME'], "www.#{park.website}")
    end
  end
end

parks_controller.rb

class ParksController < ApplicationController
before_action :find_park, only:[:park_availability]

def park_availability
  #working code...
end

private
def find_park
     # generalise away the potential www. or root variants of the domain name
    if request.subdomain == 'www'
      req = request.host[4..-1]
    else
      req = request.host
    end

    # test if there exists a Park with the requested domain,
    @park = Park.find_by(website: req)

    # if a matching site wasn't found, redirect the user to the www.<website>
    redirect_to :back
  end

end
4

1 回答 1

3

要解决有问题的错误,您可以尝试将 classname 编写为::Heroku,这将使 ruby​​ 在正确的范围内查找它。

但是 Heroku legacy api已被禁用,因此您应该使用他们的新 platform-api

heroku = PlatformAPI.connect(ENV['HEROKU_API_KEY']) # note that you may also have to use a new key
domains = heroku.domain.list(ENV['APP_NAME'])
...
heroku.domain.create(ENV['APP_NAME'], ...)

还要检查域的存在,您可以使用domain.infoapi 方法而不是获取所有不需要的域。

请记住,回调不是进行任何外部调用的最佳位置:如果 api 调用由于某种原因(临时网络问题、api 中断、服务器重启等)失败 - 整个事务将被回滚,项目将不会被保存你可以丢失数据。更好的方法是在那里排队一个后台作业,稍后将处理域,如果需要可以重试等等。

于 2020-03-25T19:16:39.610 回答