How to leverage browser caching in Rails 4? - javascript

I am using GTMetrix to see my site speed and it is showing me this (check below image).
How can I Leverage browser caching to speed up the site loading speed in Rails 4?
To defer parsing JS, I have already put
<%= javascript_include_tag 'application' %>
before /html tag.

I would recommend using separate web server, like NGINX to set cache headers for .js and .css files, removing the hassle of serving static files from Rails.
If you really wanna go with a pure Rails (app/web)server, the solution is putting this piece of code in config/environments/production.rb
RAILS 5
config.public_file_server.headers = {
'Cache-Control' => "public, s-maxage=#{365.days.to_i}, maxage=#{180.days.to_i}",
'Expires' => "#{1.year.from_now.to_formatted_s(:rfc822)}"
}
RAILS 4
config.static_cache_control = "public, s-maxage=#{365.days.to_i}, maxage=#{180.days.to_i}"

Related

Ruby on Rails - Check where assets (.js) is loaded

Im building a application where I give my clients a .js file so they can include into <head></head> and that .js file is providing some functions to my clients website.
Basically the .js file is the path to show.js.erb view. I am looking for protecting my code and looking for a way so clients/users can't just load the http://localhost:3000/js_files/2.js path on their browser and see the code.
Every client has different ID (.js path) and different website and I can detect that from my db. Is there a way so I see if the file/path is loading from my clients website and if Yes load/show the js code, otherwise not showing anything.
In other words, a way to check if file is loaded on for ex: mydomain.com or if they just copy the path into their browser.
I have read about obfuscate, but its not useful in my case.
You can use request.base_url and getting users domain name from database.
request.base_url helper:
Basically request.base_url, takes only the domain name and removed all other parts.
ex: http://domain.com/q/45/rails => domain.com
Here is my code:
<% if request.base_url == #domain.website %>
// JS CODE
<% end %>
If I understood it correctly, you want to check if your clients copied the js file on their assets or if they are using your domain on the script SRC attribute.
You think something like this may work?
Add a XHR get/post to your domain on your JS
Your domain receives the request and process the referer of the XHR (you can check on your controller on rails through request.env["HTTP_REFERER"])

How do I include custom javascript on/for a single page in Rails?

I have an interactive header for my site located in /views/layouts/_header.html.haml.
I want all the JavaScript for the header to be collected into a single file. Most importantly, I'm using Twitter Typeahead and Bloodhound for a search field with auto-suggest. A lot of this JavaScript has to be run after the header is rendered, so its inclusion in application.js (which is included on my page in application.html.haml) doesn't work, as this runs before the header is rendered.
I added search-bar.js under /assets/javascripts/ which contains all the JS I need to run on this page.
At the bottom of my _header.html.haml I just linked with a regular script tag.
%script{src:"/assets/movie-search-bar.js", type:'text/javascript'}
This works fine locally, but on my dev server I get a 404 for that asset. Is it possibly throwing out the static file for performance reasons? Even if it does work, by having it included in the asset pipeline, wouldn't the script be loaded twice (once as an individual script, and once in application.js)?
I'm getting the impression that this is not the best way to isolate the javascript of a partial into its own file. What is the best and most "railsy" way to ensure that the script is loaded once, after _header is rendered, and isolated within its own JavaScript file?
EDIT: Could this perhaps be as simple as moving the following lines to the bottom of my footer partial? Is this considered good practice in Rails?
#{ stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true }
#{ javascript_include_tag 'application', 'data-turbolinks-track' => true }
You can use javascript_include_tag on scripts other than application.js. First, make sure your script is in app/assets/javascripts folder: app/assets/javascripts/movie-search-bar.js.
Then use the javascript_include_tag helper in your view:
javascript_include_tag 'movie-search-bar'
And tell Rails to precompile that asset.
config.assets.precompile << "movie-search-bar.js"
Well I have done this task .If you want to include a particular javascript in your view .First create a folder in your views folder .For example page_js and then create some partial like _file.html.erb .And place your javascript into it .And then render that file wherever you want .So your javascript will work for that particular page only .If it doesn't work then tell me .

Devise logout not working

I'm using the latest version of devise and rails 4.2.4.
I've my home page
public/index.html
which contains heavy javascript. But when I load it from some other page, it doesn't load with all the effects. So included
$(document).on('page:load', ready);
<script src="/js/modernizr-2.6.2.min.js"></script>
<script src="/js/main.js"></script>
in application.js file.
But then
Logout
<%= link_to "Logout",destroy_user_session_path, method: :delete %>
doesn't work! It gets rendered as GET /users/sign_out.
When I remove those links from application.js, it works fine.
Any workaround for this issue?
Your javascript has an error in it.
--
Each time you use method: :delete or method: :patch, Rails populates a form with the appropriate verb, using Javascript to set it correctly:
[link_to] dynamically creates an HTML form and immediately submit the form for processing using the HTTP verb specified. Useful for having links perform a POST operation in dangerous actions like deleting a record (which search bots can follow while spidering your site). Supported verbs are :post, :delete, :patch, and :put. Note that if the user has JavaScript disabled, the request will fall back to using GET
The above is true if your javascript is broken (IE you have an error preventing it from working properly on the page).
--
Since you haven't posted your JS, I cannot give you any specifics.
However, I can say that your JS should be as unobtrusive as possible.
Using <script> anywhere in your Rails app is bad practice; you should have the files concatenated in your application.js with the help of sprockets manifest directives:
#app/assets/javascripts/application.js
//= require main
//= require modernizr
The issue is that most browsers do not support the DELETE method, the request will actually be submitted as GET, with a data-method="delete" attribute. This relies on the "Unobtrusive scripting adapter for jQuery" (jquery-ujs) being loaded by your page.
If you were using the standard rails templates, the 'application.js' manifest file would take care of that for you, but given that you are putting your index.html in the public directory you will have to manually include both jquery and jquery-ujs in your header.
An alternative is to change the route to logout to actually use GET (you will anyway have issues with the PUT and PATCH methods as well), adding this to your devise config (from devise wiki):
# config/initializers/devise.rb
# The default HTTP method used to sign out a resource. Default is :delete.
config.sign_out_via = :get
If you plan to use rails you should find out why you are having issues with the standard rails way of dealing with view templates. I use a lot of javascript-heavy pages, and they work just fine. Plus you get all the benefits of the asset pipeline.

Rails app sending javascript to client when loading whole page, but not when clicking link_to root_path?

When I refresh my Rails app or press enter on localhost:3000 in the browser, my app loads
'/' correctly and displays to the console
Started GET "/assets/*"
for all assets my app has to send.
But when I click a link which is produced from
link_to root_path
it displays the GET '/' in the console correctly, but it does not do a GET on all the assets,
thus causing all elements on the webpage which use my javascript to not work.
How can I remedy this?
Edit: Using rails version 4.1.6
Based on what limited information has been provided in the question, I believe that you are likely on Rails 4 and this is due to Turbolinks.
If you want to disable turbolinks you can follow the following steps
Remove the gem 'turbolinks' line from your Gemfile.
Remove the //= require turbolinks from your app/assets/javascripts/application.js.
Remove the two "data-turbolinks-track" => true hash key/value pairs from your app/views/layouts/application.html.erb.
Place = javascript_include_tag 'application' at the bottom of application.html
Place = stylesheet_link_tag 'application', :media => 'all' at the top of application.css in the head tag
These steps are outlined by Steve Klabnik here Removing Turbolinks from Rails 4
The following is not a direct answer to your question, but some additional elaboration on Turbolinks.
The intent of Turbolinks is to decrease page reload times by not requiring the browser to recompile the JavaScript and CSS between each page change. By default a new Rails 4 application is opted-in to this. Since the JavaScript is not reloaded on every request you can no longer use your standard DOMContentLoaded or jQuery.ready() methods of triggering your code.
Turbolinks fires supplemental events on document that you would need to opt-in to instead, such as page:load
For more complete information if you are interested in going this direction you can view additional details in the turbolinks github repo.

Ruby on Rails: How to transfer dynamic data from server to javascript?

RoR has controllers that render views. One day I wanted a controller not only to render a specific view, but also to run some javascript code using data from contoller (#product, for example) after rendering.
1. Inline javascript
So I went to my products/show.html.erb and wrote something like:
<%= javascript_tag "alert('#{#product.name} is just awesome!')" %>
2. Assets with server data
But we're all grown up boys and know about unobtrusive javascript, so I included some javascript files to my layout:
<%= javascript_include_tag "#{params[:controller]}/#{params[:action]}" %>
and then went to app/assets/javascripts/products/show.js.erb and wrote:
$(document).ready(function(){
alert('<%= #product.name%> is just awesome!');
});
But than I remembered that assets are being precompiled in production and continued to think.
3. HTML data attributes
Another way to pass some data to javascript is by using html5 data attributes in view files:
<div class="product" data-product-name="<%= #product.name %>">
Then in your asset you can write something like:
$(document).ready(function(){
$('*[data-product-name]').each(
alert($(this).data('product-name') + ' is just awesome!');
);
});
4. One more request to server
Anyway if you want to be able to cache your view files and assets, it seems as if the only way to transfer data to javascript is by using an additional Ajax request. I wonder if it is good practice to create a separate action that will send #product to client?
Can anyone say, what is the nicest way to send data from server to a javascript while rendering a view and why?

Categories

Resources