Heroku + Rack-Rewrite - ruby-on-rails

Still can't get this working...Rails 3.1.3, Ruby 1.9.2 on Heroku's Cedar Stack.
Trying to use https://github.com/jtrupiano/rack-rewrite to make http://domain 301 redirect to http://www.domain to no luck (app works, but no redirects happen at all).
/config/initializers/rack_rewrite.rb (MyAppName is actually the correct name, domain.com is actual domain):
MyAppName::Application.config.middleware.insert_before(Rack::Lock, Rack::Rewrite) do
r301 %r{.*}, 'http://www.domain.com$&', :if => Proc.new {|rack_env|
rack_env['SERVER_NAME'] != 'www.domain.com'
}
end
Added to Gemfile:
gem 'rack-rewrite'
Did "gem install rack-rewrite", "bundle install".
No luck.
Any ideas?
UPDATE:
I have figured out PART of the problem. Since I'm just trying to serve "index.html" and it's "/style" folder, it appears that having "index.html" in "/public" overrides the rack-rewrite. If I remove "index.html", the rewrites work...but now I don't know where to put the files, or set up the routes.rb to direct to the index.html page by default...any help?

change
rack_env['SERVER_NAME'] != 'www.domain.com'
to
rack_env['SERVER_NAME'] == 'domain.com'

I think that maybe env["SERVER_NAME"] could be an internal dns in this case like 'app7009.intra.foo'. I do some stuff with domains in middleware in heroku: I look at both env['REQUEST_URI'] and env['PATH_INFO'], mainly because the POW-server I use locally doesn't set REQUEST_URI. It's a bit different how different servers populate the env hash, I wish this URL request part would be more standard with something like rack.
env['REQUEST_URI'] !~ /www.domain.com/

I'm new to this so I have no logical explanation as to why it works but it worked for me when I put the codes in config/application.rb instead of a new file /config/initializers/rack_rewrite.rb.

Related

Upgraded Rails to 6, getting Blocked host Error

I needed the new function in ActiveStorage to resize_to_fill so I upgraded to Ruby 2.5.1 and Rails 6.
ruby '2.5.1'
gem "rails", github: "rails/rails"
When I stopped, then restarted my server (Cloud 9), I received the below Rails error:
Blocked host: xxxxxxx-xxxxxxx.c9users.io
To allow requests to xxxxxxx-xxxxxxx.c9users.io, add the following configuration:
Rails.application.config.hosts << "xxxxxxx-xxxxxxx.c9users.io"
I've tried restarting, new windows, but nothing worked. I've never seen this error before. I'm guessing the new version of Rails is doing something?
The Blocked Host is a new feature of Rails 6. You can add this pattern to your config/environments/development.rb to have no worries of that in case of dynamic urls
config.hosts << /[a-z0-9]+\.c9users\.io/
Also for ngrok user, just replace above c9users by ngrok
Update: ngrok is currently using - and . as subdomain in their URLs so this should be accurate config.hosts << /[a-z0-9-.]+\.ngrok\.io/
Source: https://github.com/MikeRogers0/puma-ngrok-tunnel
If you want to disable this functionality on your development environment, you can add config.hosts.clear to config/environments/development.rb.
Add this line to config/environments/development.rb
config.hosts << /.*\.ngrok\.io/
Restart your rails server and it will work
This article worked for me:
The first option is to whitelist the hostnames in config/environments/development.rb:
Rails.application.configure do
config.hosts << "hostname" # Whitelist one hostname
config.hosts << /application\.local\Z/ # Whitelist a test domain
end
The second option is to clear the entire whitelist, which lets through requests for all hostnames:
Rails.application.configure do
config.hosts.clear
end
Credit goes to Manfred Stienstra.
To allow requests from any subdomain of ngrok.io (or other service), the simplest solution is to prepend it with . like so:
# config/environments/development.rb
Rails.application.configure do
...
config.hosts << '.ngrok.io'
end
No need to use a regexp for subdomains like mentioned in some other answers.
PS: don't disable this functionality by doing config.hosts.clear as mentioned in some other answers, as this defeats the purpose of Rails' DNS rebinding protection, and under the right circumstances an outside attacker could gain full access to your local Rails app information (source).
In Rails 6 Action Pack introduced ActionDispatch::HostAuthorization and by default allows only [IPAddr.new(“0.0.0.0/0”), IPAddr.new(“::/0”), “localhost”]
You can add arrays of RegExp, Proc, IPAddr and String or a single String in the file config/application.rb like this
class Application < Rails::Application
config.hosts << "xxxxxxx-xxxxxxx.c9users.io"
...
end
From "https://drivy.engineering/rails-6-unnoticed-features":
Rails 6 added a new middleware called
ActionDispatch::HostAuthorization allowing you to whitelist some hosts
for your application and preventing Host header attacks. You can
easily configure it with a String, IPAddr, Proc and RegExp (useful
when dealing with wildcard domains).
I added Rails.application.config.hosts << "xxxxxxx-xxxxxxx.c9users.io" to config/application.rb and it fixed my test app fine. Then I did it to my real app and it also worked. The problem is, Devise threw an error as well, which apparently won't be fixed until at least Rails 6 beta. I guess I'm going back to Carrierwave for my image sizing needs until ActiveStorage is more mature.
In Rails 6, when you want to allow host from ngrok v2.3.40, add this config into config/environments/development.rb
config.hosts << /[a-z0-9\-]+\.ap\.ngrok\.io/
Restart server and enjoy
Add this line to config/environments/development.rb
config.hosts << /.+\.ngrok\.io:\d+/
Most of the responses I see are missing the port part of the URL. If you are accessing this URL in a specific port (typically :3000) the :\d+ part of the regular expression is necessary.
It will work after restarting your server.
config.hosts = nil
Use this in development.rb and and restart your rails server, it works for me, it will work.
HEADS UP : You may whitelist your host with the config application.config.hosts << 'your_unvalid_host_name' but still have the error.
The error message is currently not accurate in this case. See this issue.
You should not use hostname with underscore.
NB: The application.config.hosts.clear is working in this case.
In order to support hyphens in the ngrok subdomain name and region, you need to change config/environments/development.rb change config.hosts to /[a-z0-9.-]+.ngrok.io/
Example:
config.hosts = (config.hosts rescue []) << /[a-z0-9.-]+.ngrok.io/
1st run the ngrok 3000 in one of the terminals and next open the new terminal and run rails s... then u can see now ngrok and rails s both can run simultaneously...

Rack Rewrite before force_ssl Rails > 3.2 Heroku

I'm using Rack Rewrite to 301 redirect my apex/root domain to my www domain because my wildcard SSL doesn't support the root domain. I'd also like to force SSL sitewide but can't seem to get my rewrite to occur before the force SSL. I've tried a few things, namely the response in this answer: https://stackoverflow.com/a/8217170/535632
Here's my rewrite code:
Gospot::Application.config.middleware.insert_before(Rack::Runtime, Rack::Rewrite) do
if Rails.env.production?
r301 %r{.*}, Proc.new {|path, rack_env| "http://www.#{rack_env['SERVER_NAME']}#{path}" },
:if => Proc.new {|rack_env| rack_env['SERVER_NAME'] == 'mydomain.com'}
end
end
I've tried:
require 'rack/ssl'
Gospot::Application.config.middleware.insert_before(Rack::SSL, Rack::Rewrite) do
Instead of using config.force_ssl = true in production.rb but I get the following error on Heroku:
No such middleware to insert before: Rack::SSL (RuntimeError)
Is there anyway to run my rack rewrite before the force_ssl? I've found a lot of answers but they all seem to work for Rails < 3.1
I ran into the same issue where I wanted to use rack-rewrite to redirect based on the domain before forcing SSL. I was able to accomplish this in Rails 4 by inserting the Rack::Rewrite middleware before ActionDispatch::SSL as shown in the code below.
config.middleware.insert_before(ActionDispatch::SSL, Rack::Rewrite) do
# redirects / rewrites here
end
The easiest way to do this, depending on your DNS provider, would make your apex DNS record a CNAME for your www subdomain.
If that won't work for you, then you should find a middleware that does exist in your stack to place this rewrite before. Try this:
heroku run rake middleware
To get an idea of what your middleware stack looks like. Choose a piece of middleware that's relatively high up the chain and place the rewrite before it. There's definitely some guess and check that will be going on here, probably, but this will eventually correct your problem.
I had the same problem (Rails 3). Apparently force_ssl adds Rack:SSL to the top of the middleware. To insert before it you have to add it as a string or else you will get an "uninitialized constant" error.
Here is the code I ended up using:
SM::Application.config.middleware.insert_before("Rack::SSL", Rack::Rewrite) do
# rewrite code
end

Using url_helpers in a coffeescript file with a base url in production

I am trying to use Rails url_helpers inside of coffescript files. I append the .erb extension to the filename (profile.js.coffee.erb) and use ERB to access the helpers like so:
jQuery ->
window.Intl.Models.Profile = Backbone.Model.extend
url: '<%= Intl::Application.routes.url_helpers.profile_path %>'
This works great in development and it will return /profile. In production, I am using a URL root of /intl so I tell the asset pre-compiler to consider this in deploy.rb
set :asset_env, "#{asset_env} RAILS_RELATIVE_URL_ROOT='/intl'"
However, this doesn't seem to affect the url_helpers because it will still return /profile instead of /intl/profile
I tried setting ENV["RAILS_RELATIVE_URL_ROOT"] in production.rb and development.rb respectively and that didn't work either.
Any suggestions would be appreciated. Thank you.
You may need to set this at the Rack level. If you are using Passenger, you can set the RackBaseURI directive.
Same problem here.
As a partial solution I use
set :asset_env, "#{asset_env} RAILS_RELATIVE_URL_ROOT=/csc"
in deploy.rb for Capistrano deploymment. This works fine for all other aspects of the asset precompilation except this single aspect (.coffee.erb) wich seems completely unaffected by that setting.

What does "WARN Could not determine content-length of response body." mean and how to I get rid of it?

Since upgrading to Rails 3.1 I'm seeing this warning message in my development log:
WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
What does this mean and how can I remove it? Is it a problem?
Asked the same question to one of Rails-Core's members:
https://twitter.com/luislavena/status/108998968859566080
And the answer:
https://twitter.com/tenderlove/status/108999110136303617
ya, it's fine. Need to clean it up, but nothing is being hurt.
The following patch solved the problem in my case; no more warnings for me.
204_304_keep_alive.patch
Just edit the file httpresponse.rb at line 205 as shown at the link above; in fact the link shows a correction made to a future release of Ruby.
I'm using rails 3.2.0 on ruby 1.9.3-p0 installed through RVM as a single user. So the location in my case is:
~/.rvm/rubies/ruby-1.9.3-p0/lib/ruby/1.9.1/webrick/httpresponse.rb
The location of the file to be altered differs depending on the type of installation, RVM or not, or even multi-user or single user, so I'm just giving the last part of it:
.../ruby-1.9.3-p0/lib/ruby/1.9.1/webrick/httpresponse.rb
I hope this can be helpful to someone.
EDIT: This is the link to the commit that altered the line in question in the trunk branch of ruby project.
Just explicitly adding the Gem to the Gemfile got rid of the warning messages for me:
group :development do
gem 'webrick', '~> 1.3.1'
end
You can also use Thin instead of the default Webrick.
Add this to Gemfile
gem 'thin'
then rails s thin will use thin, and the warning will disappear.
If you're using .rvm, do this to fix it...
As mentioned by João Soares, all credits to him, this is what you can do if you wan't to get rid of this warning on development.
Use your favorite editor to open this file:
~/.rvm/rubies/<ruby-version>/lib/ruby/1.9.1/webrick/httpresponse.rb
Go to the line that contains this(for me it was really line 206):
if chunked? || #header['content-length']
Change it, taken from this patch, to this:
if chunked? || #header['content-length'] || #status == 304 || #status == 204
Save the file and eventually restart your rails server
This problem has been fixed in Ruby's trunk branch with this commit to webrick.
You can edit this particular webrick file similarly in your setup. The approximate location can be found by:
gem which webrick
To actually edit the file:
nano \`ruby -e"print %x{gem which webrick}.chomp %Q{.rb\n}"\`/httpresponse.rb
(Or instead of nano, use your favorite editor.)
JRuby version: If you're using .rvm, do this to fix it...
As mentioned by João Soares and Kjellski, this is what you can do if you want to get rid of this warning on development and you are using JRuby.
Use your favorite editor to open this file:
~/.rvm/rubies/jruby-<version>/lib/ruby/<1.8 or 1.9>/webrick/httpresponse.rb
Go to the line that contains this (for me it was line 205):
if chunked? || #header['content-length']
Change it, taken from this patch, to this:
if chunked? || #header['content-length'] || #status == 304 || #status == 204
Save the file and eventually restart your rails server.
Another workaround that removes the offending line from webrick. It's just not that useful:
cd `which ruby`/../../lib/ruby/1.9.1/webrick/ && sed -i '.bak' -e'/logger.warn/d' httpresponse.rb
(you may need to sudo)
Add
config.middleware.use Rack::ContentLength
to your application.rb file, and the warning will disappear even with webrick. This will also set Content-Length properly in production when rendering a json or text response.

How to get the subdomain value from a url?

how can I get the subdomain value in rails, is there a built-in way to do this?
e.g.
test123.example.com
I want the test123 part of the url.
Rails 3.0 has this capability built-in, you can access the subdomain from request.subdomain.
You can also route based on the subdomain:
class SupportSubdomain
def self.matches?(request)
request.subdomain == "support"
end
end
Basecamp::Application.routes do
constraints(SupportSubdomain) do
match "/foo/bar", :to => "foo#bar"
end
end
If you're using 2.3, you'll need to use a plugin such as subdomain-fu.
Use the following method inside your controller
request.subdomains
This Returns an array of subdomains
account_location is also a good plugin. After using it, you can find the account based on different subdomains. And you can find out subdomain from url just by writing request.subdomains(0).first in your code.
In case you are working with a string, and assuming it can be a true URI, you can do this to extract the subdomain.
require 'uri'
uri = URI.parse('http://test123.example.com')
uri.host.split('.').first
=> "test123"
https://stackoverflow.com/a/13243810/3407381
Simple in your controller just do the following
unless request.subdomains.any?
#No domains available redirect
redirect_to subdomain: 'www'
end
You can use the SubdomainFu plugin. This plugin gives you a method current_subdomain which returns the current_subdomain of your app.
You can also have a look at this Railscast
UPDATE
You can also use request.subdomains this will give you an array of subdomains.
For anyone looking to get the subdomains on localhost using WEBrick:
Put config.action_dispatch.tld_length = 0 into config/environments/development.rb and everything should work.
Link to SO post here:
Can I make Rails / WEBrick recognize entries in /etc/hosts as subdomains (instead of domains)?
Link to Github post:
https://github.com/rails/rails/issues/12438
current domain with subdomains:
"#{request.subdomain}.#{request.domain}"
# or
"#{request.subdomains.join(".")}.#{request.domain}"
A bit late to the party but here's what I used in older versions of rails.
subdomain = request.subdomains.join('.')
It should be backwards compatible in newer versions

Resources