In my rails app, I'm trying to create a booking form external parties(parks
) can point their customers to to make a booking for the respective park. The booking form works with the url/route with the subdomain book
https://book.myapp.com/en/parks/:park_id/park_availability
Goal
I would like substitute my domain (myapp.com
) with the website of the park
, such that I get
https://book.parkapp.com/en/park_availability
Unfortunately I get the error message(s) upon creation park
NameError (uninitialized constant #<Class:0x0000563d7bf62250>::Heroku):
when using an existing park
{park.website}'s server IP address could not be found.
Outline attempted approach
Park
has awebsite
column. Inroutes.rb
I tried setting up the constraints and apply them on thepark_availability
action.- In the
Park
model I attempted to add the domain (Park.website
) to my Heroku application, once the park is saved. - In my
Park controller
I try to find the@park
, before thepark_availability
action.
Code
routes.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
park.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