I'm trying to setup Subdomains in Rails 3 per Ryan Bates screencast on subdomains. However it's not working for me. I have the following setup:
# routes.rb
constraints(Subdomain) do
get 'devices' => 'devices#all'
end
# lib/subdomain.rb
class Subdomain
def self.matches?(request)
# binding.pry
request.subdomain.present? && request.subdomain == "admin"
end
end
Loading the url admin.localhost:3000/devices
should route me to devices#all
, however I get a routing error Routing Error No route matches [GET] "/devices"
Clearly my routing isn't working.
I setup a pry
debug session where the comment is above, and it gets hit, so my constraint is working, but I get the following output:
[1] pry(Subdomain)> request.subdomain
=> ""
[2] pry(Subdomain)> request.subdomains
=> []
[3] pry(Subdomain)> request.host
=> "admin.localhost"
So rails isn't picking up the admin portion of the url and placing it into the subdomain variable. While I could easily just use the host value to filter to the admin routes, I'd like to keep things clean and correct.
How come rails isn't setting the subdomain value?
Edit
Both jdoe and coreyward are correct with their answers. What was throwing me off was that I was also using pow
and xip.io
to access the site and getting the same error. Which was odd because http://admin.app_name.192.168.1.68.xip.io/devices
has a tld > 1. What was happening was that the subdomain for xip
was admin.app_name.192.168.1.68
, which also fails given the matches logic and doesn't route.
To define routes for multiple subdomains, we just have to add multiple constraints blocks in our routes.rb file. Rails routing provides request constraints and segment constraints. Segment constraints add rules on the request path whereas request constraints add conditions on the incoming request.
In today's post, we'll learn how to build a Rails app that can support multiple subdomains. Let's assume that we have a gaming website funkygames.co and we want to support multiple subdomains such as app.funkygames.co, api.funkygames.co, and dev.funkygames.co with a single Rails application.
Certain routes can't be placed inside the subdomain constraints. A typical example is healthcheck or ping endpoints. If we are using a load balancer in front of our Rails app, the load balancer needs to periodically check if the app is up or not.
Though the constraints based subdomain routing works in most cases, it can be a pain in certain situations. When we are working with third-party APIs and building integrations, the local development TLDs such as .local or .dev are not allowed.
Because there isn't a subdomain as far as Rails considers it.
Rails expects you to provide a Top-Level Domain (TLD) length for TLDs with more than 1 dot. For example, if you had bbc.co.uk
it would pickup "bbc" as the subdomain unless you specified the TLD length is 2, in which case the subdomain would be blank:
request.subdomain(2) #=> ""
This is also why you're seeing subdomains
return an empty array: the last two segments are being discarded automatically. You could specify 0
as the TLD length to get back "admin", but that code will break in production with a real domain name, so I don't recommend it.
I recommend using a domain like admin.yourapp.dev that is routed back to your computer via localhost to make your app properly detect a subdomain. Just edit /etc/hosts to do it simply.
If you're curious, here is the Rails source for the subdomain
method.
Try using special address: http://admin.lvh.me:3000/devices
Or set:
config.action_dispatch.tld_length = 0
in your development.rb and restart your app.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With