I am creating a rails landing page for a client and he wants the app to be a subpage of his website.
app.herokuapp.com
website.com/app
How can I configure the domain so that when the user types website.com/app
The app.herokuapp.com appears instead?
Edit.
Obs. The client website is big and runs on WordPress installed on domains.com
I am new to rails and the domain services, sorry if it is too of a basic question.
Heroku must run the rails app in the root of your domain. So basically what you're trying to do is impossible using just Heroku and whatever domain service.
However the desired result can be achieved by making the whole thing a rails app but with namespaces. This can only work if the website is doesn't require a server to run. i.e it's static with just HTML, CSS and JS but with no framework like Angular or CMS like WordPress. Here's an outline of the steps one would need to take to do that:
First of all, to make your "rails app" exist in /app, you can move all the "application related" routes to an "app" namespace.
In your routes.rb:
Rails.application.routes draw do
namespace :app do
# all application routes should be placed in here
end
end
You need to move all your app related controllers to a /controllers/app.
All the application controllers need have their classes renamed to have the proper namespace. So you need to change every class WhateverController < ApplicationController to class App::WhateverController < ApplicationController
You need to move all the application related views to /views/app
This step is a little tricky. And it's only necessary if the assets (css, javascript) differ between the website and application. You need to create app.js, website.js, app.css, website.css that will live in /assets/javascripts and /assets/stylesheets respectively. You also need to create "website" and "app" folders in both /assets/stylesheets and assets/javascripts. Move all the application related assets to the corresponding /javascripts/app and /stylesheets/app folders.
Add the following code:
To app.js:
//= require_tree ./app
To app.css:
*= require_tree ./app
Change your application.html.erb layout's assets links to:
<%= stylesheet_link_tag 'app', media: 'all' %>
<%= javascript_include_tag 'app' %>
The above code tells the layout to look for app.js and app.css and include what they require. And what they require is everything in the `/app/ folders you have in the different assets folders.
If you push/deploy to Heroku, the application should live in website.com/app (provided you've pointed "website.com" properly to Heroku. See Reference).
The next batch of steps is to make the website live within the rails app in the root namespace.
Move all the required website assets (html, css, javascript) to the corresponding /javascripts/website and /stylesheets/websites folders in your assets folder.
Add the following code:
To website.js:
//= require_tree ./website
To app.css:
*= require_tree ./website
Create a new layout (website.html.erb). It should look very similar to application.html.erb except:
<%= stylesheet_link_tag 'website', media: 'all' %>
<%= javascript_include_tag 'website' %>
Now you can create the controller that will manage the website pages (WebsiteController) in /controllers.
class WebsiteController < ApplicationController
layout 'website' #we need to tell it which layout to use
def homepage
end
def about
end
#basically just create methods/actions for every page on the website
end
For every action, create a corresponding view in /views/website. For example the homepage view should be homepage.html.erb. Also copy and paste the HTML from the website into the right .html.erb files.
To tie it all up with routes.
root 'website#hompepage'
get '/about' => 'website#about'
get '/contact' => 'about#contact'
#and so on...
namespace :app do
# all application routes should be placed in here
end
Finally make sure to go through all the markup everywhere to replace all link_to paths and src for img tags. Even the paths for the app would need to be changed because all the routes have been changed.
Another option would be to use the high voltage gem to add the static website html to your rails app.
Related
My site is both available as:
www.site.com
site.com
I want the www.site.com to be the primary site. In case a user visits the naked site the header should have a canonical link to the www site. Is there any easy way to do this in Rails? I should be done for all pages from a certain controller. (not all controllers since the site is multi tenant through subdomain: like client1.site.com etc...)
Note: This comment has been heavily edited upon clarification from the original poster
To set a canonical link in Rails, you can use the canonical-rails gem: https://github.com/jumph4x/canonical-rails
Install the gem and then you can do:
rails g canonical_rails:install
Which will put a canonical_rails.rb file into config/initializers. Open that file and define your canonical url by adding this line:
config.host = 'www.yourapp.com'
Then, if you have an app/views/layouts/layout.html.erb file or similar, you can add:
<%= canonical_tag -%>
to the <head> portion of your view.
I've read through a number of StackOverflow threads and tutorials, and I haven't found a good, simple explanation for how to allow a user to download a file from your site.
All I want to do is add a link to one of my views which downloads a file when clicked.
I'd like to understand:
Where do I store the downloadable file in my file system? public?
Is there anything special about linking to the file in your view, or it's just a link_to?
What needs to happen in routes? It's just a get for that controller#action?
What needs to happen in the controller? In rails documentation I've read that you need to "be careful to sanitize the path parameter if it is coming from a web page," but I'm not sure exactly what that means.
Thanks!
In simple scenario, you don't need controller to download file. Just save file to public folder. Public folder is default folder for static resources there are stored compiled js, css, images files, robot.txt and so on.
If you have file monthly-report.doc. Put it to public/reports/monthly-report.doc.
In view link_to 'Donwload Report', '/reports/monthly-report.doc'
There are basically two cases:
1. The file is public and should be downloadable by anyone.
Place it in the /public directory. Remember that this is the web root - so if you have a file that lives at /public/foo/bar.baz you would link to the file with <%= link_to 'A file', '/foo/bar.baz' %>.
No routes or controllers are need since we are just serving a static file from the servers public directory.
2. The file needs access control
In this example we are dynamically servering files stored in /downloads.
# routes.rb
resources :downloads, only: [:show]
class DownloadsController < ApplicationController
# do your authentication logic here
# GET /downloads/:id
# #example
# GET /downloads/foo.bar would download a file stored at
# /downloads/foo.bar
# #raise [ActiveRecord::RecordNotFound] if the file does not exist.
# This causes a 404 page to be rendered.
def show
fn = Rails.root.join('downloads', params[:id])
raise ActiveRecord::RecordNotFound and return unless file.exists?(fn)
send_file(fn)
end
end
By using Rails to serve the download we can apply whatever access control rules we want.
The link_to is the same as any other link.
If you want to store it in public then do this in whatever controller action you want.
send_file File.join(Rails.root, 'public', 'file.extension')
You could create a downloads controller and specify that in the index then simply link_to 'Download', download_index_path or such.
If you're trying to send a file name that a user inputs, you have to sanitize it. If it's "hard coded" like the above example, then you're fine.
There are several ways to include controller-specific assets in Rails:
One option which is not DRY is to add = yield :head in the layout and content_for(:head) { ... } in every top-level view. If an asset is controller-specific, it should be specified only once per controller, not in each view. Of course, this approach is awesome for view-specific assets.
A second option which is not declarative is to add an asset corresponding to the controller name if it exists. Instead of checking whether something exists, I should simply say (where appropriate) that it exists and must be included. Also, I'm not sure if the response would be cached to avoid a runtime performance hit. On the positive side, this approach wouldn't require any changes to views or controllers, but it might open up the possibility for name clashes, especially with legacy models.
A third option is to include all assets of a type in a single file. Browsers shouldn't download assets they don't need, and this would make it more difficult to debug the application. This option would be fine if the total asset size is still manageable.
Is there some way to declaratively include a single controller-specific asset in a separate file in a DRY way without breaking the MVC model using very little code?
Rails will serve only the code in the controller specific asset files to the specified controller if you use the following include commands in your application layout:
<%= javascript_include_tag params[:controller] %>
<%= stylesheet_link_tag params[:controller] %>
I suspect if you do this you will need to also do the following:
Still include the <%= javascript_include_tag :application %> and <%= stylesheet_link_tag :application %> to get all your cross controller assets
Check how the require_tree . directives work to ensure that the controller specific assets are not being loaded both by the application.css and the <%= stylesheet_link_tag params[:controller] %> in fact you may need to remove the require_tree . and load any cross controller sheets directly into the application files
See the Rails Guide on the Asset Pipeline in section 2 for more information.
how to display the image, which stored outside from the project directory?
Is there a simple way to do it?
I see two ways :
On top of your rails server, in production and sometimes in dev, you have to use a web server like apache or nginx. With these, you can serve files from other directories for specific URL. E.G. you can make http://yourapp.com/images/ serving files from a specific dir. In rails, display the image with a traditionnal image_tag
Example with Nginx :
# Find the right `server` section which you currently use to serve your rails app
server {
listen 80;
# Add this
location /images {
root /var/www/my/specific/folder;
}
location / {
#...
#... Here you should already some code to proxy to your rails server
}
}
With that, when you access to `yourserver.com/images`, nginx serve your specific folder and not your rails app. Then in your app view :
<%= image_tag 'http://yourserver.com/images/my_pic.jpg' %>
If you can't access your server settings, you can serve an image file from a controller action with send_file
In a controller :
class ImagesController < ApplicationController
def show
send_file File.join('/var/www/my/specific/folder',params[:name]), :disposition => 'inline'
end
end
In config/routes.rb
match '/images/:name' => 'images#show', :as => :custom_image
Then when you access this action (via the route you defined in config/routes.rb), you have the image. So in your view you do a traditionnal image_tag with this URL :
<%= image_tag custom_image_path( 'my_pic.jpg' ) %>
OR
<%= image_tag custom_image_url( 'my_pic.jpg' ) %>
If it's stored outside of the Rails app directory, then it does not belong to asset pipeline and you can simply link to it:
<%= image_tag("http://example.com/some_file.jpg") %>
Obviously it must be accessible through HTTP (you need nginx or Apache server installed).
This is probably bad idea and will lead to a bunch of issues. Some security, some functionality, but most of the effects I actually don't know.
I do know, from experience, that whenever you go against the rails conventions for what and where stuff is, it's a slippery slope of things breaking, best avoided.
Create a solution using the framework provided.
Note this functionality can also be affected a bit if you are using rails 3.1+ as opposed to <= 3.0 due to asset compilation which copies js, css and images into public.
I want to run my Rails application in a different scope so that I can deploy it in a war file (mydepartment.war) which will share a Tomcat instance with another Java app WAR. The solution I chose was to modify the rackup file (/config.ru).
map '/mydepartment' do
run Myapp::Application
end
When I do this, my base URL becomes http://localhost:3000/mydepartment instead of just http://localhost:3000. The application runs fine, but it doesn't download CSS/JS specified by stylesheet and script helpers.
However, when I try to include stylesheets and Javascript using helpers, such as
<%= stylesheet_link_tag :all %>
<%= javascript_include_tags :defaults %>
The URLs they generate include localhost:3000/javascripts/jquery.js instead of localhost:3000/mydepartment/javascripts/jquery.js. I actually tried typing the latter in the browser, and the sheet downloads fine.
How can I coax the Rails Javascript/CSS helpers to download files in the new scope without hardcoding it?
if you're not on rails 3.1:
Add this to your config/environments/production.rb (if on production mode):
config.action_controller.asset_path = proc { |path| "/mydepartment#{path}" }