So far I have in config/routes.rb:
match 'doc/:path' => 'doc#show'
And in app/controllers/doc_controller.rb:
class DocController < ApplicationController
layout false
def show
render File.join( RAILS_ROOT, 'doc', params[:path] )
end
end
This works find for index.html and other .html files. But it doesn't serve up .css and .js files. It also doesn't serve nested files and directories such as /doc/metrics/output/index.html
How can I get Rails to serve up all static files in /doc but without simply putting a link to them in /public (so that I can autheticate the user in the controller first)?
I would recommend not serving the files through Rails at all. Serve them through your server (Nginx, Apache). You can use the X-Accel-Redirect and the X-Sendfile headers to tell Nginx and Apache to send the static file instead. The benefit of this approach is that you can still authenticate a user before allowing them access to the file. Here's the Nginx tutorial:
http://ablogaboutcode.com/2010/11/19/serving-static-files-passenger-nginx/
Another option is to setup your routes like this:
match 'doc' => 'doc#show'
And pass your path as a parameter so you don't have to do nested URL matching in your routes, or handle special cases (.css, .js, .html, ...)
/doc?path=/path/to/my/document.css
Related
We have a multi-tenacy CMS running on RAILS. When Google reads sitemap.xml It pulls the default favicon.ico in our system. That is the icon for the CMS itself. We need it to show the icon for the domain it is referencing. My thought was to put the ICON in the DB and have it serve as system serves any other data. However RAILS just servers the default path of the physical file.
Any Ideas on how to override or overwrite the default route???
The files in the /public aren't overrideable, as far as i know.
You could move the favicon.ico from your /public folder to /public/images and define a custom route:
get 'favicon.ico', to: "favicons#show"
Then, in the favicons controller you can check the current domain from the request and return the according favicon based on that.
class FaviconController < ApplicationController
def show
host = request.host
# Find the corresponding favicon file based on the host
send_file file.path, filename: 'favicon.ico', disposition: :inline
end
end
To make sure that you don't have to make a request for the default favicon every time, define a favicon_tag in your layout if it hasn't already been defined -
= favicon_link_tag '/images/favicon.ico'
My root is site/home/ubuntu/workspace/
Is it possible to access file (from browser by HTTP request) located inside workspace/ without configuring routes and controllers?
Does the question on 1) depend on file extension?
you can access path to your file like this:
File.expand_path("somestuff.rb", "~/workspace")
for me this code produces path as follows:
"/home/foodie/workspace/somestuff.rb"
I have this structure:
# /home/username/Workspace/rails_project/app/controllers/application_controller.rb
require "#{Rails.root}/../test.rb
And
# /home/username/Workspace/test.rb
# Some ruby code
As you can see, test.rbfile is outside RubyOnRails Project.
For security reason, you can not access a file outside project rails from URL without defining a route. What you can do, is point a route to controller that, based on file name provided at url, require a file outside rails project.
# /home/username/Workspace/rails_project/config/routes.rb
get '/get_file/:file_name', to: 'files#show'
# /home/username/Workspace/rails_project/app/controllers/files_controller.rb
class FilesController < ApplicationController
def show
document = params[:file_name]
send_data "#{Rails.root}/../#{document}, filename: document
end
end
For more info, see:
http://api.rubyonrails.org/classes/ActionController/DataStreaming.html#method-i-send_data
Without configuring routes and controllers, client can only access files in the public/ directory (it doesn't matter what the extension is). Bare in mind this: when your Rails app is run by webserver, its webroot will be the public directory, consequently to access public/file.ext you request should be webroot/file.ext
I would like to use a different public folder from a parent directory called client which contains the entire AngularJS app. Essentially I want to tell Rails to load AngularJS app and the only job that Rails has to do is serve JSON.
Is that possible in Ruby on Rails?
As others have mentioned, it may or may not be a great idea to override the existing paths['public'] folder. But you can do the following safely in somewhere like application.rb:
Rails.application.config.middleware.insert_after(
ActionDispatch::Static,
ActionDispatch::Static,
Rails.root.join("client").to_s,
Rails.application.config.static_cache_control
)
The public folder is exposed to the web server through the Rack middleware ActionDispatch::Static. There's nothing else special about it, and the above code simply adds another instance of the middleware that points to the directory client. So in the above case, the browser would be able to access everything in public as well as client.
Just had to do it myself for an Angular app.
Put this in your application.rb:
config.serve_static_files = true
paths['public'] = File.join 'client', 'app'
Or if you still use asset pipeline (config.assets.enabled = true):
paths['public/javascripts'] = File.join 'client', 'app', 'scripts'
paths['public/stylesheets'] = File.join 'client', 'app', 'styles'
Would be interesting to know if there are any consequences with the second bit as my front-end is served completely separately thus I keep asset pipeline switched off and use grunt instead.
You can define another path like
# config/application.rb
paths['my_website'] = 'website'
Then you can use this path in your routes like
# routes.rb
get '/my_website', to: redirect('my_website/index.html')
I'm using the static site generator Middleman to build my site. We currently have landing pages that we proxy via config.rb as such:
# landing page template directories to redirect
landingpage_seo_templates = Dir['source/landingpages/seo/*.erb']
# point all landingpage/seo templates to the root
landingpage_seo_templates.map! do |tpl_name|
tpl_name = File.basename(tpl_name).gsub(/.erb$/, '')
proxy "/#{tpl_name}/index.html", "/landingpages/seo/#{tpl_name}.html", :ignore => true
end
This points all of the files in a directory from /landingpages/seo/{filename}.erb to the /{filename}.erb when the site is built. However, this doesn't work for sub-folders.
My question is how would I modify this script to render the sub-folders. For examples I would like files in /landingpages/seo/foo/{filename}.erb to render to /foo/{filename}.erb
I know how to do this via .htaccess, however I'd like to learn how to do this via config.rb.
Thank you in advance.
If you modify your file pattern ...
landingpage_seo_templates = Dir['source/landingpages/seo/**/*.erb']
... you should get all erb templates in the seo tree.
You then need to modify the tpl_name computation (there probably is a smarter/shorter way for that):
# point all landingpage/seo templates to the root
landingpage_seo_templates.map! do |tpl_name|
tpl_name = tpl_name.gsub(/.erb$/, '')
tpl_name = tpl_name.gsub(/source\/landingpages\/seo\//, '')
proxy "/#{tpl_name}/index.html", "/landingpages/seo/#{tpl_name}.html", :ignore => true
end
I am porting a 2.x rails app to rails3; we'll call it foo-app. Foo-app is one section of a larger rails app and lives at main_rails_app.com/foo-app. Previously we just set up the following in our foo-app production config to ensure that our foo-app routes worked properly:
ActionController::Base.relative_url_root = "/foo-app"
However, with rails3, I now get:
DEPRECATION WARNING: ActionController::Base.relative_url_root is ineffective. Please stop using it.
I have since changed the config entry to the following:
config.action_controller.relative_url_root = "/foo-app"
This mostly works in that all calls to external resources (javascript/css/images) will use /foo-app. However, none of my routes change appropriately, or put another way, foo-app root_path gives me '/' when I would expect '/foo-app'.
Two questions:
What is the replacement for ActionController::Base.relative_url_root
if it is config.action_controller.relative_url_root, then why are my routes not reflecting the relative_url_root value I set?
You should be able to handle all that within the routes.rb file. Wrap all your current routes in scope; for instance.
scope "/context_root" do
resources :controller
resources :another_controller
match 'welcome/', :to => "welcome#index"
root :to => "welcome#index"
end
You can then verify your routing via the rake routes they should show your routes accordingly, including your context root(relative_url_root)
If you deploy via Passenger, use the RackBaseURI directive: http://www.modrails.com/documentation/Users%20guide%20Apache.html#RackBaseURI
Otherwise, you can wrap the run statement in your config.ru with the following block:
map ActionController::Base.config.relative_url_root || "/" do
run FooApp::Application
end
Then you only have to set the environment variable RAILS_RELATIVE_URL_ROOT to "/foo-app". This will even apply to routes set in gems or plugins.
Warning: do not mix these two solutions.
I feel like I must be over-complicating this and/or missing something, but this issue has been frustrating me for a while now, and here are my notes.
Summary
There are two separate issues with two points each for dynamic and static routes:
how to get routing to correctly match an incoming URL
for routes
for static files
how to generate URLs that include the relative_root
via url helpers
for static assets
One way to solve all four points:
Configure Nginx to strip the relative_root portion
This solves route matching; just write routes expecting URLs at / like development
Also static files are served as in development
Set RAILS_RELATIVE_URL_ROOT environment variable
This solves generated static asset helpers
Use the ScriptName middleware below (modify it to use the value from the environment)
This solves generated url helpers, e.g. users_path
Wrapping the Rails application in Rack::URLMap in config.ru (Christoph's answer)
# config.ru
map '/relative_root' do
run Myapp::Application
end
requires incoming URL contain the relative_url_root (Nginx can be configured to remove or retain this; see below)
Rack appends the relative_url_root to the Rack env SCRIPT_NAME rack/urlmap.rb:62
Rails adds the current request's SCRIPT_NAME to url_for options metal/url_for.rb:41
Rails' url_for prepends the script name when generating paths routing/url_for.rb:133
So that covers URLs generated by the url helpers, e.g. given UserController, users_path will be prefixed by the relative url root.
Set SCRIPT_NAME in middleware
# config.ru
class ScriptName
def initialize(app, name)
#app = app
#name = name
end
def call(env)
env['SCRIPT_NAME'] += #name
#app.call(env)
end
end
use ScriptName, '/relative_root'
run Rails.application
Has same effect as above, but
Requires that incoming URL NOT contain the relative_url_root
Setting RAILS_RELATIVE_URL_ROOT
value is saved in app.config.relative_url_root configuration.rb:41
which in turn affects asset paths asset_url_helper.rb:137
but that's it as far as I see
notably does not affect url helpers
Setting config.action_controller.relative_url_root
?? May affect assets compilation?
Overrides RAILS_RELATIVE_URL_ROOT env var?
Explicitly defining all routes under /relative_root (rizzah's answer)
# config/routes.rb
Myapp::Application.routes.draw do
scope '/relative_root' do
...
end
end
Url helpers will generate correct urls
Incoming URL must contain the relative url root (sensitive to Nginx configuration, see below), else "no route matches" exceptions
URLs requesting static assets, e.g. /relative_root/images/logo.png will result in "no route matches" exceptions. This may not be an issue if nginx is serving static assets anyway.
Nginx config
Given a config like this:
upstream myapp {
server localhost:3000;
}
server {
...
location /relative_root {
proxy_pass http://myapp/;
}
}
Nginx will strip out the /relative_root, and the Rails app will not see it. If you need the Rails app so see it, one way is to change the proxy_pass line:
...
proxy_pass http://myapp/relative_root/;
...