I created a new Rails app and when I am in some view of a controller called Welcome, if I check the source code I see that the welcome.css is being added, even though I don't specify that in the layout or explicitly anywhere in my code.
However, in another Rails app when I am in a controller, let's call it welcome, whenever I am in the view, I don't see the welcome.css being loaded.
How does Rails decide whether yes or not require the css for a specific controller? From the Rails guides it seemed to me that you have to specificly add the stylesheet_link_tag params[:controller] in order to load the specific css, but this is not the case in my first application, where I don't set that anywhere.
By default in rails 3.2, rails adds a stylesheet_link_tag in the app/views/layouts/application.html.erb
<%= stylesheet_link_tag "application", :media => "all" %>
and requires all your stylesheets in the app/assets/stylesheets/application.css
*= require_self
*= require_tree .
that's the reason why your rails 3.2.2 app adds all your stylesheets automatically. if you don't want to load all your stylesheets, just edit these two files.
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 am using the Controller-specific Assets configuration, it woks perfectly except with the newly installed [Rails-Devise] authentication bundle (https://github.com/plataformatec/devise).
For instance on registration page (controller devise/registrations), The assets on /stylesheets/devise/registrations.css and /javascripts/devise/registrations.jsare not loaded (404).
Devise works fine when I reactivate both the
application.js
//= require_tree .
and
application.css
*= require_tree .
but :
Is it possible to add devise gem's assets in a way that allows to keep the controller specific assets ?
Thanks,
Devise doesn't have any stylesheet or javascript assets.
--
You'll be best using some conditional logic in your layout, to determine whether you're using a devise_controller or not:
#app/views/layouts/application.html.erb
stylesheet_link_tag :application, (controller_name unless devise_controller?)
This uses the devise_controller? helper
I'm actually building a new app under Rails 4.
I used to put my javascript_includes_tag at the bottom of my layout. But for an unknown reason, it creates a bug when trying to use confirm: on delete link.
So I put back this line at the top :
!!!
%html{ :lang => 'en' }
%head
= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => true
= javascript_include_tag "application", "data-turbolinks-track" => true
So far so good, the bug is now gone. Anyway, since my app is gonna use a lot of Javascript, I still need to load those third part library at the bottom. So, what I did is to only let the Rails library at the top :
// application.js
//= require jquery
//= require jquery_ujs
//= require turbolinks
Then I tried to create another js file named third-part and try to do the same as application but including my third part libraries. Unfortunately, it does not work.
// third-part.js
//= require bootstrap
//= require app
//= require app.plugin
How can I add another javascript_includes_tag at the bottom the same way I did for application? Here I mean that on production it will also compress those files.
Thanks a lot for your help
EDIT :
It's actually loading my files well on DEVELOPMENT, but not on my production.
On production I just got <script data-turbolinks-track="true" src="/javascripts/third-part.js"></script> and I can't access the file
I've tried :
config.assets.precompile += %w( third-part.js )
and
rake assets:precompile RAILS_ENV=production
but it still not working
EDIT 2 :
I made a test of precompliling on production mode from my local machine. It did work. It might be a problem with my server.
EDIT 3 :
Just earse my application from server and clone a new one from my Github but it's still not working. Don't know why :(
In your config/environments/production.rb add this line to precompile the external assets
config.assets.precompile += ["third-part.js"]
and don't forget to mention env=production while precompiling assets on production.
I added a custom engine for HAML in config/initializers.
When I visit http://127.0.0.1:3000/assets/page.html it renders the page successfully.
# page.html.haml
!!! 5
%html{:lang => "en"}
%head
= stylesheet_link_tag 'application'
= javascript_include_tag 'application'
The problem is Rails seems to cache the html asset. When I add or remove a file from the application.js manifest it doesn't update until I stop the Rails server and run rake tmp:clear. An alternative is to touch the application.js file. I have config.assets.debug = true set because I prefer to see individual files/folders in Chrome DevTools rather than one big application.js file.
Is there a way to exclude certain assets from being cached during development.
Just to reiterate - its the HTML being cached which is the problem, changes to the manifest are reflected when visiting http://127.0.0.1:3000/assets/application.js.
A brute force solution would be to add some depends_on attributes to the haml file:
# page.html.haml
#= depend_on application.js
#= depend_on application.css
!!! 5
%html{:lang => "en"}
%head
= stylesheet_link_tag 'application'
= javascript_include_tag 'application'
This should force the asset to be regenerated when the application.js file is changed.
There are a few cavets with this. The file names should be the names in the source tree. It assumes you can use # for comments in your HAML renderer (I don't know HAML so I'm not sure).I'm also not really sure how this works with a custom engine. Also, a better solution would be to have your custom HAML engine track dependencies itself, but I don't know how to do this.
See the sprockets docs for more details
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.