Best way to include javascript in Rails via content_for - ruby-on-rails

I have some pages in my Rails application that need one off bits of javascript to be included, ideally just before the </body> tag. There is no real need to have this javascript included on EVERY page since most don't use it. I've found a way to make this work, but I think the code is terrible.
How would you do the same thing or how would you refactor the existing code?
View simplified, sample code on gist.github.com:
https://gist.github.com/scottswezey/ffc7bf52041b976b710a
(Or see the same code below:)
application.html.erb (Layout):
<!DOCTYPE html>
<html lang="en">
<head>
...
</head>
<body>
...
<script>
$(function() {
<%= yield(:js) %>
});
</script>
</body>
</html>
some_view_file.html.erb (View):
<%
str = <<END_OF_STRING
$('.modal').modal()
END_OF_STRING
content_for :js do
str.html_safe
end
%>

Don't ever do it this way: JavaScript doesn't belong in HTML. Just put an appropriate <script> tag in the page, referring to an external JS file, something like this:
application.html.haml
!!!
%html
%head
= yield :javascript
%body
= yield
view file
- content_for :javascript do
= javascript_include_tag 'modal'
app/assets/modal.js
$(document).ready(function() {
$('.modal').modal();
}
This keeps everything nicely separated.

Is it possible to add a .js.erb partial with your JS and render it under the body?
edit: Check out this answer: https://stackoverflow.com/a/10113547/1283742

Related

Rails 5.2: How do I use page specific JS scripts when using Turbolinks?

I am writing some exploratory javascript for a page. It includes the following line:
dashboard_settings.addEventListener('ajax:complete', function(){
...
I have placed the script just before the closing body tag.
I notice that when I navigate to the page, the JS works as I expect it to and there are no error messages in the console. However, when I navigate away from the page, an error message displays in the JS console:
Uncaught TypeError: Cannot read property 'addEventListener' of null
I understand that this is something to do with turbolinks. However, I am unsure how to go about avoiding it without turning turbolinks off.
Is there any way at all that I can specify that the script loads for the one page only?
I have tried the following without success:
<%= yield :page_scripts %>
<% content_for :page_scripts do %>
<script>
document.addEventListener('turbolinks:load', function(){
...
You can add the listener only if the element exists.
if (dashboard_settings)
dashboard_settings.addEventListener('ajax:complete', function(){...})
Or, if you wan't to add it only for a specific page, you could add a yield statement on your layout and only set it's content con the desired page
#layout
<html>
<body>
...
</body>
<%= yield(:after_body) -%>
</html>
#your view
<%= content_for :after_body do -%>
<script>
document.addEventListener('turbolinks:load', function(){
dashboard_settings.addEventListener('ajax:complete', function(){...})
})
</script>
<%- end -%>

Turbolinks + lightbox (Rails 5)

I know this question has been asked to death but I still can't resolve things in my app. I'm running a rails 5 app (with turbolinks and the fancybox lightbox gem) and have some page-specific javascript to display images on model show pages:
application.html.erb
<head>
...
<%= javascript_include_tag "application", "data-turbolinks-track" => true %>
...
</head>
<body>
...
<%= yield :page_scripts %>
</body>
show.html.erb
<% content_for :page_scripts do %>
<script type="text/javascript">
$(document).on('turbolinks:load', function() {
$("a.fancybox").fancybox();
})
</script>
<% end %>
I still get the classic response whereby the image loads up nicely upon first page visit or page refresh. Navigating away and back again stops the lightbox from working (seems to just hang in my case).
How do I use the 'turbolinks:load' feature to get this to work properly?
just use {parent: 'body'} and it will fix the issue with Turbolink.
$("a.fancybox").fancybox({parent: 'body'});
credit: Kirill Platonov
You can change into below code.
$(document).ready(function() {
document.addEventListener("turbolinks:load", function() {
$("a.fancybox").fancybox();
})
});
I hope this help you. You can go to details through this link turbolinks.
I'm not sure if this fully qualifies as an answer, but given that the scenario in this link was very similar:
https://github.com/fancyapps/fancybox/issues/1413
....I ended up following their advice and removing turbolinks from the show page using data-turbolinks="false".
I am not familiar with tubolinks, but keep in mind that $("a.fancybox").fancybox() simply binds click event to current elements. So, you probably have to reattach it after navigating. Another possible solution would be to use event delegation using selector option, example (using v3.1):
$().fancybox({
selector : '[data-fancybox="images"]',
animationEffect : "fade"
});

Changing between layouts requires refresh to see changes

In my controller, I've got my show action using a different layout (e.g., foo.html.erb) than my application.html.erb. foo.html.erb has styles loading directly in the <head>, for example:
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
{styles here}
</style>
</head>
<body>
<%= yield %>
</body>
</html>
Here is the controller code for how I'm resolving the layout:
class FoosController < ApplicationController
layout :resolve_layout
def show
end
private
def resolve_layout
case action_name
when 'show'
'foo'
else
'application'
end
end
end
The problem is, the application seems to cache the templates too heavily, and when I click through to a view that should be using the show template, I don't see those <head> styles without a refresh.
Am I handling this correctly, or is there a more "rails way" of doing this? What I'm really trying to accomplish here is having styles unique to a particular template only load with that single template. I think this may be an asset pipeline question, but I'm not sure, as I'm still new to Rails.
Seems like it was an issue with the styles living in the head. I had a relatively simple page, so I was able to move them to be inline styles, and the problem seems to be solved.

Rails - use code(css, js, html) from server on client side

I had a application rails built with bootstrap and simple form.
Here I have to show the UI patterns how they actually look like. That means I have to show the
patterns like menu bar, accordian patterns examples in my application. For that I am storing the pattern code html,css,js in database.
Here my requirement is I have to show the actual code pattern view from the stored record(css,js,html) without any css/js conflicts.
How can eneter the html,css,js code dynamically in a partial or page to show that
in a fancybox in rails.
Thanks for the help in advance.
just use html_safe or raw to render your content as a normal string on views. For instance:
in your controller:
#x = YOUR_CODE_FROM_DB
in your view:
<%= #x.html_safe %>
# <%= raw #x %> is also ok in this case
NOTICE: you can use html_safe on models, but raw is declared on a helper, so you can just use it on controllers and views.
-- edit --
more example:
on controller:
#hello = 'alert("hi");'
#body = 'body{ background: red; }'
on view:
<script type="text/javascript" charset="utf-8">
<%= raw #hello %>
</script>
<style type="text/css" media="all">
<%= #body.html_safe %>
</style>

Partial rendered via ajax does not contain javascript when it should

I have a partial that is being rendered via ajax and the result used to replace a div's contents. This partial is rendering correctly but when I inspect the element the javascript tag and it's javascript is not rendered in the browser. The partial is similar to the following
<style>
/* some styles */
</style>
<script type="text/javascript">
alert("did it work");
</script>
<% #array.each do |el| %>
<!--make table w/ array -->
<% end %>
When i inspect the element everything is there but the javascript. and i have evalJS: true on my Ajax.Updater options (i'm using prototype but i don't think that makes any difference). The odd thing is that when i put the following in the action i can see the rendered template in the console w/ the js
test = render :partial => "my_partial.html.erb"
puts test
test
Any help would be greatly appreciated.
If you look here: http://api.prototypejs.org/ajax/Ajax/Updater/ you will notice that the correct option name is evalScripts (but read about its use, because it has some limitations).

Resources