How to get domain/subdomains of an app outside of controllers/views? - ruby-on-rails

How can I get the domain and subdomains of my application without being in a controller/view?
The reason for needing this is that I am subscribing to process_action.action_controller notifications within an initializer, and I need my applications' url from within that initializer.

If the host part of the URL (domain, subdomain) is dynamic ... which is to say "depends on the request" then, of course, the only way to get it is within the context of the request itself, which the controllers and views know about.
So I am assuming the application has a known host, perhaps dependent upon runtime environment (production, test, development, etc.), or maybe based on the server environment, but otherwise static. In this case, you could define a custom config variable containing the name, as noted in the more recent answer from Jack Pratt on this SO question: How to define custom configuration variables in rails.

Related

How do I add a host to my permitted rails hosts dynamically?

I need to dynamically add a permitted host to my Rails 6 application during runtime.
I've managed to append to Rails.application.config.hosts at runtime, but I'm still receiving an error Blocked host.
Rails appears to ignore the hosts added to Rails.application.config.hosts that are added outside of application.rb and initializers.
Looking at host_authorization.rb, I can't see an obvious way of asking it to listen to new hosts.
My Reasoning:
User's can programmatically create their own 'shop' on our platform, which adds a new 'tenant' (apartment gem) to our multi-tenanted application We also allow them to point their own domains to our application.
However, in order to allow traffic from their custom domain, we currently would require a manual application restart if we stick with the default whitelisted domains.
I know I could use a workaround, and just set the hosts to whitelist everything (Rails.application.config.hosts = nil), but we need to keep the platform secure and automated.
The items in config.hosts are documented as compared using the === operator, which means we may include a lambda in that array, and thus make dynamic checking possible.
For the sake of an example, let's say we're returning a global permit-list from MyApp.all_permitted_domains. Then in config/application.rb we might write:
config.hosts << ->(host) {
MyApp.all_permitted_domains.include?(host)
}
Note however that in this case the additional processing normally performed on host authorization (such as handling port numbers, or the special case of a leading ".") is not included. If you need that behaviour too, review the sanitize_hosts method in that host_authorization.rb source file for how.

Rails uses different default url options in views vs controllers?

Scratching my head over this.
Recently opened a new reverse proxy to our site via nginx to support a new domain. When you access via either old.server.com or new.server.com you hit our backend.
If you hit via old.server.com, all the url helpers work fine and produce valid absolute URLs. But if you hit via new.server.com (the new reverse proxy host) then url helpers only work correctly in views. URL helpers used in the controllers use the hostname plus the actual unicorn port -- which is incorrect for URLs we want to send out.
Even more confusing, this is only the case in the controllers. In the views, this works correctly in all cases. In order to make this work in controllers when using the new.server.com I need to override the default_url_options method in the ApplicationController.
Yes, I have both the Rails.application.routes.default_url_options[:host] and Rails.application.routes.default_url_options[:protocol] configurations setup correctly.
I feel like I probably missed forwarding some required header in the reverse proxy, but haven't figured it out. But more importantly, why are the views and controllers using different contexts for generating absolute URLs?
UPDATE:
The difference between the two hosts appeared to be the value being provided by the reverse proxy for the Host header. The "old" proxy was sending the public host for it, and the "new" proxy was sending nothing. Rails appears to use the Host header in constructing URLs in the absence of explicit data. In order to fix this I either need to set the Host header correctly or implement the default_url_options method in my controller.
So, I now have working code, but it seems like a Really Bad Idea(TM) that controllers and views are not using the exact same code/setup for creating URLs. Is this just standard rails, or did I miss some configuration?

How can I use Domain-based routing?

I have a simple web server running Windows 2012 with IIS. I have half a dozen domains linked to this server that are basically not in use yet. I have a few more domains which are used but they could all have various subdomains that aren't supported by any site yet. So I have a default site in IIS set to catch all incoming requests that aren't handled by any other site on the server or any other server. And it's main purpose is to show a "Page not in use yet" message.
That's easy to set up but I want these pages to be a bit more fancy. So I want to have some kind of routing based on the domain name so example.com and sub.example.com and sub.sub.example.com would all be handled by the same view, but anotherexample.com would be handled by a different view and thirdexample.com by yet another view. And any domain that is not caught by this routing system would go to the default view.
And I wonder if there's a simple way to do this. Something like [route("example.com")] as a controller attribute which the system would recognize as the controller for a specific domain and it's subdomains. (And the URL path can be ignored.) I don't know if something like this already exists and have used Google but found nothing yet.
I can create a custom route, of course. But this tends to result in an if-then-else situation for all potential domain names. I need to know if there's a better method.
Use the URL rewrite module for IIS:
https://learn.microsoft.com/en-us/iis/extensions/url-rewrite-module/using-the-url-rewrite-module

how to add subdomain name from current url using .htacces rules

I have a URL link like,
http://domain.com/abs/def/city and,
i want to display it as http://city.domain.com/ABC/def
using .htaccess.
Can any one help me by providing .ht access rules.
I want to write .htaccess rules for each city name in URL act as sub domain name.
Also i want it to be dynamic as there are different cities are available in site.
i am using below code in .htaccess file, but not working properly.
RewriteRule ^index.php/(.)/(.)/([^/]+)$ http://$3.domain/$1/$2/$3 [R=301,L]
is there any way to get my requirement using or by modifying my above code or by some other .htaccess code.
Sorry, but what you ask is not possible. This is a typical missunderstanding about url rewriting:
Url rewriting rewrites (manipulates) incoming requests on the server side before processing them. It is not possible to alter outgoing content such that contained urls are changed by this means.
There are solutions for that though:
apaches proxy module can "map" one url into the scope of some other url
there are also modules for automatic post processing of generated html markup
more exotic or creative solutions exist, it depends on your situation in the end...
But usually the easiest is to change the application (typically just its central configuration) such that it contains final urls (pointing to the subdomain in your case). Then you can indeed use the rewriting module to "re-map" those to the previous scope when future incoming requests refer to them (they got clicked).
Ok, second step getting additional info from your comments:
Just to get this clear: you understand that it is not possible to change the link you send out by means of rewriting, but you want to change the url shown in the browser after the user has clicked on some city link? That is something different to what you wrote before, that actually is possible. Great.
If the rewriting works as you want it to (you see the desired url in the browsers address bar), then we can go on. The error message indicates a name resolution problem, that has nothing to do with rewriting. Most likely the domain "cambridge.192.168.2.107" cannot be resolved, which is actually not surprising. You cannot mix ip addresses and names, it is either or.
Also I see that you are using internal, non-routable addresses. So you also are responsible for the name resolution yourself, since no public DNS server can guess what you are setting up internally. Did you do that?
I suggest these steps:
stop using an ip addres for this, use a domain name.
since you are working internally, take care that that domain name is actually resolved to your local systems ip address. How you do this depends on your setup and system, obviously. Most likely you need some entry in the file /etc/hosts or similar.
you need to take care that also those "subdomain names" get resolved to the same address. This is not trivial, again it depends on the setting and system you locally use.
if that name resolution works, then you should see a request in your http servers access log file. Then and only then it makes sense to go on...

How can i setup different domains to different flow3 namespace application?

I have a flow3 app that have several namespace, how can i manage to point another domain to another specific namespace ?
As far as I know, you cannot. Not directly at least. Since the FLOW routing system is ignorant of domains, there currently is no domain-switch.
What I did, was route all requests to the main package and have a routine that runs before every request (ie. in MyAbstractController->initializeAction()).
It checks if the domain of the request is not for the main package and in that case, it would trigger an internal redirect() to the other Controller/Package.

Resources