This question already has answers here:
Using Rails 3.1, where do you put your "page specific" JavaScript code?
(29 answers)
Closed 9 years ago.
I'm starting with Rails 4 and I have a couple of questions about assets.
How can I specify that a CSS just must be included in some view?
I have the same question about a JS file. I have added a JS file to app/assets/javascripts/viewname.js
however it is included in every page. I would like it to be seen just in viewname view.
Help me please!
Thanks
Save the file as /vendor/assets/javascripts/viewname.js and include it in your view with:
<%= javascript_include_tag 'viewname' %>
To include the JS file in the HTML header
Use content_for in a view file to collect content that will be rendered later.
<% content_for :head %>
<%= javascript_include_tag 'viewname' %>
<% end %>
Call yield in the layout template to render the collected content:
<head>
...
<%= yield :head %>
</head>
To automatically include a javascript file named after the current controller, you could also put this in your layout template file:
<head>
...
<%= javascript_include_tag params[:controller] %>
<%= javascript_include_tag "#{params[:controller]}_#{params[:action]}" # variant with action name %>
</head>
But that will give 404 errors for a controllers/actions without a javascript file.
Related
How would I display different versions of headers in Rails in my application.html.erb view? For instance, for my landing page, I have a pretty big header that includes a callout and some sign-up and sign-in buttons. For other static pages, I have a normal small header with a logo and a few links to the right. And for my dashboard when users log in, it will look a little different as well.
How can I display certain headers in an if/else statement where Rails will output the different versions of headers based on the current url or view in my application.html.erb?
To answer your question with an example this is what you may want to do.
Rails has a provision to use nested view templates using the content_for and yield tags.
Do the following thing to achieve what you want -
In app/views/layouts/application.html.erb - Add a ternary expression which acts as a if else. While rendering the views rails will look for a <% content_for :custom_header do %> in the view templates. If it doesn't find that it will render the partial app/views/layouts/_default_header.html.erb instead.
<html>
<head>
<title><%= #page_title or "Page Title" %></title>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
</head>
<body>
<!-- Code to conditionally load a header -->
<%= content_for?(:custom_header) ? yield(:custom_header) : render :partial => "layouts/default_header" %></div>
<!-- For the body -->
<%= yield %>
</body>
</html>
Now since you say that most pages will have a static small header, save the html code for that in a partial under app/views/layouts/_default_header.html.erb.
In you landing page (for example the the view app/views/welcome/index.html.erb) you can use the content_for tag with the identifier :custom_header that we have used in the application.html.erb
Add the following in your landing page.
<% content_for :custom_header do %>
<div class="custom-header">
<!-- Your complex header with sign in and signup links... -->
</div>
<% end %>
The ternary operator in the application.html.erb will pick up this content from the content_for tag in the landing page and insert the content in place of the yield(:custom_header).
Hope this helps.
It sounds like you may want to use a nested layout.
I am using Rails 4, Wicked_PDF and Chartkick Gem's
For Google Charts I use:
<%= javascript_include_tag
"//www.google.com/jsapi", "chartkik" %>
The html view comes up with charts and everything as expected.
When I append .pdf to the url the pdf document shows in the browser but the ChartKick charts do not show.
The following error appears where the chart should be:
Error Loading Chart: No adapter found
I have found the following online in the PDFKit documentation.
Resources aren't included in the PDF: Images, CSS, or JavaScript does
not seem to be downloading correctly in the PDF. This is due to the
fact that wkhtmltopdf does not know where to find those files. Make
sure you are using absolute paths (start with forward slash) to your
resources. If you are using PDFKit to generate PDFs from a raw HTML
source make sure you use complete paths (either file paths or urls
including the domain). In restrictive server environments the root_url
configuration may be what you are looking for change your asset host.
I am assuming that wkhtmltopdf is not finding the link to the charts, but I am not sure how to fix this.
Does anyone have a suggestion?
I found this link:
Render jQuery in wicked_pdf
Where Unixmonkey helps FattRyan to solve this for Highcharts.
Can anyone help how to set this wicked_pdf_javascript_include_tag so that Wicket_PDF will accept charts from Chartkick using Google charts?
You have to specify a protocol http or https when referencing to a CDN inside the pdf layout.
Also chartkick is served via the assets pipeline, so use wicked_pdf_javascript_include_tag instead.
Replace this line:
<%= javascript_include_tag "//www.google.com/jsapi", "chartkik" %>
With this:
<%= javascript_include_tag "https://www.google.com/jsapi" %>
<%= wicked_pdf_javascript_include_tag "chartkick" %>
That's how I do it in a project of mine.
Cheers.
I struggled with this for a bit and the other answers were only partially useful for me. I wanted to provide more detail for anyone in the future:
The 4 major things I did to fix this for us were:
(1) Not using the middleware approach and instead using one off ruby embedded pdfs based off of a PDF layout you create
#Example layout file
#app/views/layout/pdf.pdf.rb
<!DOCTYPE html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<%= wicked_pdf_stylesheet_link_tag "print" %> #print specific stylesheet
<%= yield :head %>
</head>
<body>
<h1>PDF Report</h1>
<%= yield %>
</body>
</html>
(2) using wicked_pdf's asset helpers to load ONLY the javascript we needed on those pages for assets we store in the app (all CDN based assets can be loaded with a normal javascript_include_tag)
#Example page template for a PDF you're downloading
#app/views/users/profile.pdf.erb
<% content_for :head do %>
<%= javascript_include_tag "some_cdn.com" %>
<%= wicked_pdf_javascript_include_tag "chartkick" %>
<% end %>
<p>All your pages content</p>
(3) using the javascript_delay option
#Use it universally from the initializer or on the specific PDF rendering in the controller
#config/initializers/wicked_pdf.rb
WickedPdf.config = {
javascript_delay: 3000,
other_options...
}
(4) pass the "discrete" axis option otherwise we only saw the axis and no data for time based charts (line/area/etc.)
#In the above template, wherever you render your chart
#app/views/users/profile.pdf.erb
<% content_for :head do %>
<%= javascript_include_tag "some_cdn.com" %>
<%= wicked_pdf_javascript_include_tag "chartkick" %>
<% end %>
<%= area_chart #data_retriever.time_based_data, discrete: true %>
<%= pie_chart #data_retriever.other_data %> # the default is discrete: false so no need for another option
Add the following to the top of the view your trying to convert to a pdf:
<%= wicked_pdf_javascript_include_tag "application", "chartkick" %>
I got it to work with Alex Villa's answer and from the answer to a similar question by installing the latest wkhtmltopdf version then specifying the javascript_delay option in the controller in step (3):
respond_to do |format|
format.html
format.pdf do
render pdf: "filename",
javascript_delay: 3000,
template: 'template_path.pdf.erb',
layout: 'pdf.html'
end
end
If someone gets the same issue with Rails 4 in 2019, then try to freeze chartkick version on 2.3.5. Because from the 3.0.0 version they removed support for Rails < 4.2. See
chartkick CHANGELOG
gem 'chartkick', '2.3.5'
Add this at the beginning of head in your pdf view file:
<%= javascript_include_tag "https://www.google.com/jsapi" %>
<%= wicked_pdf_javascript_include_tag "chartkick" %>
And replace the wkhtmltopdf-binary gem with wkhtmltopdf-binary-edge. I used 0.12.4.0 version.
gem 'wkhtmltopdf-binary-edge', '0.12.4.0'
That's all I did and it worked.
I am working on a Rails 4 app in application.html.erb I have the following code
....
<head>
<title>...</title>
<%= javascript_include_tag "application", "data-turbolinks-track" => true %>
<%= yield :head %>
<%= csrf_meta_tags %>
</head>
What this does is allows me to load certain assets depending on the page I am on. So maybe in the show template of a certain action I could do something like
<% content_for :head do %>
<%= stylesheet_link_tag "show" %>
<% end %>
This works great and helps me keep the page structured clean and simple. The issue I am having now is that turbolinks is completely ignoring these assets and not even loading them when I click on a next link. I have looked around but cant seem to find an answer to this problem. Any help will be appreciated.
I had the same problem, try to add data-turbolinks-track into your stylesheet tag
This is most likely because turbolinks does not replace the <head> element:
Turbolinks makes following links in your web application faster. Instead of letting the browser recompile the JavaScript and CSS between each page change, it keeps the current page instance alive and replaces only the body and the title in the head. Think CGI vs persistent process.
As such, any changes to the <head> element will be ignored.
Is it possible to manipulate the placeholders so that I can not only set their content, but also add/remove content in a particular order? For example:
layouts/base.html.erb (a base layout meant to be extended):
<!DOCTYPE html>
<html>
<head>
<title><%= yield :title %></title>
<%= yield :stylesheets %>
<%= yield :javascripts %>
<%= yield :csrf %>
</head>
<body>
<div class='container-fluid'>
<%= yield :header %>
<%= content_for?(:content) ? yield(:content) : yield %>
<%= yield :footer %>
</div>
</body>
</html>
layouts/application.html.erb (this is the layout I will be using for the most part of my app, it inherits from the base layout):
<% content_for :stylesheets do %>
<%= stylesheet_link_tag "application", :media => "all" %>
<% end %>
<% content_for :javascripts do %>
<%= javascript_include_tag "application" %>
<% end %>
<% content_for :csrf do %>
<%= csrf_meta_tags %>
<% end %>
<%= render :template => 'layouts/base' %>
Now I want a layout for a specific controller, which may need to add more javascript links, or maybe completely remove them. Let's say I want to add only one file after the other javascripts. So far I got this:
layouts/some_controller.html.erb (this is a layout for a particular controller, it should inherit from the application layout):
<% content_for :javascripts do %>
<script src="/assets/some_javascript_that_depends_on_jquery.js" type="text/javascript"></script>
<% end %>
<%= render :template => 'layouts/application' %>
This won't work, because it will place some_javascript_that_depends_on_jquery.js at the beginning of the :javascripts placeholder, and I need it at the end because it depends on jquery.
It would suck to have to extend the base layout directly, and keep track of any change made to the application layout to apply it to the controller-specific layout too.
What would be the recommended way to deal with this situation?
In application.html.erb, Keep the contents of content_for :javascripts in a partial
Here your partial will have
<%= javascript_include_tag "application" %>
Then, call the same partial in addition with other javascripts in other layout.
Another way,
You can call one helper which will have a hash like this:
js_files = {"application_controller" => ["js_file_1"], "some_controller" => ["js_file_1","js_file_2"]}
Now, fetch the js files and construct the javascript include tag in run time based on controller in your content for.
Hope this will be more flexible.
Sorry for not formatting.
Always keep one js file per controller.
<%= javascript_include_tag params[:controller] %>
lets take example of users controller then there will be users.js.coffee file.
If you want to have multiple js files for users controller then you can require those files inside users.js.coffee file
vi users.js.coffee
//= require 'a'
//= require 'b'
/* my extra js code will go here */
This can't be done as in other frameworks where you just extend layouts and then modify the inherited blocks at will.
Rails sort of forces you to keep it simple.
I'm following the Ruby of Rails getting started guide, and I see this code in the layout file:
<!DOCTYPE html>
<html>
<head>
<title>Blog</title>
<%= stylesheet_link_tag "application" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body style="background: #EEEEEE;">
<%= yield %>
</body>
</html>
Coming from an MVC3 background, is this the equivalent to the RenderContent() method one would invoke from the _layout.cshtml file?
The functionality is about the same in that context, yes. However, yield in general is a keyword in the ruby language, concerning blocks. You can find more information here: ruby blocks.
Building on that, you are able to provide content for different parts, using content_for(:something) and yield :something (the yield passes :something to the layout engine, the layout engine fills in the content for it).