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}" }
Related
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.
I have a rails app in production with apache2 and passenger. But some of my images didn't appeared so i changed the path inside the 'image_tag' like this:
<%= link_to image_tag("/assets/#{product.image_url}", {:title => "Push it into cart!"}), line_items_path(product_id: product), method: :post %>
After this all work fine in production. But when i try in development, i got this error:
Sprockets::Rails::Helper::AbsoluteAssetPathError in Store#index
Asset names passed to helpers should not include the "/assets/" prefix. Instead of "/assets/cs.jpg", use "cs.jpg"
What i should do to make it work in both enviroments?
image_tag works without using /assets/ path as long as you have the asset pipeline enabled (which is the default) and your image is in app/assets/images/ folder. If your image is outside that folder it won't get precompiled so you'll have to add it to the asset precompilation, in your config/environments/production.rb add
config.assets.precompile += ['image.jpg']
I think that for your problem you shouldn't store the images of your products in the assets folder as this is used for the application images not for you content (models) images, those should be stored in the public folder public/uploads is commonly used for that by gems like paperclip
You should never use /assets/ prefix, it's possible that you just need to precompile assets for production.
rake assets:precompile RAILS_ENV=production
It also depends on where are you using the said asset, for example, when using it in stylesheet you should use image-url('image.jpg') rails css helper. When using it inline in the view, you use the image_tag helper, as you have.
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 have a Rails app which is not using the asset pipeline. The assets are managed by Yeoman (http://yeoman.io/) and Grunt tasks. We recently introduced a browser cache busting task called grunt-rev to revision the assets before deploying. This task re-names the assets with some uniqueness, then flow passes on to another task called grunt-usemin which updates the html and css files with the new asset names before copying them to the public folder.
For example, main.css in index.html looks like:
<link rel="stylesheet" href="styles/main.css">
And will be re-witten to:
<link rel="stylesheet" href="styles/f43ce6bf.main.css">
The Rails app works fine with local development as the assets are dynamically generated by Yeoman. But once deployed, the assets public folder contains all the revved assets and the Rails views (written in haml) cannot find them. Links like the one below are now dead...
%link{:href => "/styles/main.css", :media => "screen,print", :rel => "stylesheet"}
So I've come up with a few ideas I think might work.
Symlink main.css -> f43ce6bf.main.css
Add a view helper to find the assets
Inline the javascript & css into the view as it is not too big
Fork grunt-usemin to add haml support, then run it against the views within Rails
But am not sure whats best? or am I missing a much easier solution?
UPDATE: I'm now using the helper like below
module ApplicationHelper
def busted_css
#busted_css ||= begin
if Rails.env != "development"
File.join("/styles",
File.basename(Dir["public/styles/*main.css"].sort_by {|f| File.mtime(f)}.reverse[0])
)
else
"/styles/main.css"
end
end
end
end
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.