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?
Related
I am using node.js and ejs for my template, and I included the header.html which contain all the libraries and style files, for all my html files.
The problem that I have is that it reloads all the html, css, and js when I switch between html files (e.g: home.html and about.html).
How can I cache the js and css files and avoid reloading them when I render?
Is there a easy and convenient way (plugins) to swap out the body content and not reload header.html every time for every html files?
HTML files (home.html and about.html)
<% include header.html %>
<body>
<% include navbar.html %>
<% include menu.html %>
</body>
Route files for home.html and about.html
router.get('/', function(req, res) {
req.getConnection(function (err, conn) {
res.render('home', {data: rows});
});
});
I need to perform alot of querys in the back-end, and needs to return the data to the front-end.
What you are asking to do is build an application that loads data that will remain static while certain area(s) of the site a dynamically changed based on user interaction or whatever.
This is called a single page application (SPA https://en.wikipedia.org/wiki/Single-page_application), and the main technology involved with this is AJAX. There are many approaches to doing this and many frameworks such as AngularJS, Knockout etc that help you do this as well.
If you are loading new page states via server-side code then your architecture will need to be refactored or preferably rebuilt if you wish the achieve this effect the right way. Every time your user has a page refresh, all of the data must be re-sent to the user and because of this you will have to resend the entire view (data and dom nodes script includes images etc..) with each update you wish to perform on the UI.
You may server cache some things, or even client cache pages that the user has not been to yet... but without ajax there is really no way around the fact that you must reload the entire page each time you wish to make an update.
There are more demos of how to build this with NodeJS than there are fish in the ocean, but here the most popular one on my SERP results https://scotch.io/tutorials/creating-a-single-page-todo-app-with-node-and-angular.
I have a js file called create.js.erb that is in my view folder. It's supposed to be called when I try to create a record, but it isn't being called. I can't figure out why, and to be totally honest, don't even know how my app calls a js file in the view folder, so I'm not sure what code to paste here to help debug the problem.
Can anyone explain to me how js in a view folder is executed, and when I would want to put a js file in my view folder instead of in the asset pipeline?
*.js.erb files are rendered when you are using AJAX/JS with your controller actions. By default, when you call the create method, Rails will respond using HTML. This will load a new page. Sometimes you want to use AJAX instead, and that's why you create js.erb files in the view folders.
For this to work, the form and/or link_to objects you are using must be AJAX enabled (they should have a :remote => true attribute on them) If they are not specified as remote forms, they will execute the HTML instead of the JS and the create.js.erb file will never be called.
Your controller method also needs to know how to respond to js requests. You need something like:
respond_to do |format|
format.js
end
That code tells Rails to look for a file called "method".js.erb in your view folder, so in this case, create.js.erb.
These files are completely different from regular JS files you put in the asset pipeline -- these are view templates to be rendered as the result of a controller action.
You might find some Rails/AJAX tutorials helpful...here's a pretty good one that walks you through this whole process:
http://net.tutsplus.com/tutorials/javascript-ajax/using-unobtrusive-javascript-and-ajax-with-rails-3
Hope that helps, if you need more assistance please post the code for your controller and any of the view files...
I'm trying to upload a file to my Rails application with ajax. To facilitate this, I have included the jQuery.remotipart gem.
// app/assets/javascripts/application.js
//= require jquery.remotipart
I have a form for uploading files. These files are processed by CarrierWave.
<%= form_for #import, remote: true do |f| %>
<fieldset>
<%= f.label :file, "Attach a CSV file" %>
<%= f.file_field :file %>
</fieldset>
<%= f.submit :upload %>
<% end -%>
Unfortunately, when I submit the form with a file attached, it doesn't seem to arrive at my controller action correctly. The params hash has stringified JS objects as keys.
Started POST "/file_imports" for 127.0.0.1 at 2012-11-06 01:00:49 +0000
Processing by FileImportsController#create as JS
Parameters: {"object Object"=>{","=>{"object Object"=>{","=>{"object Object"=>nil}}}}}`
In Chrome's Dev Tools, I can see that this is indeed the form data that is being sent to the server:
The form works perfectly when I remove remote: true (of course, it sends a HTML request rather than a JS request in that case).
Anyone have any idea what I'm doing wrong? By the way I'm using Rails 3.2.8 and Remotipart 1.0.2 (latest).
Edit: Did some more digging.
Looking into the Remotipart source, I can't seem to understand what it is supposed to do. For example, in vendor/assets/javascripts/jquery.remotipart.js, Line 22 has the following:
settings.data = form.serializeArray();
A little further down, the settings are sent to the server via $.rails.ajax(settings).
The $.fn.serializeArray() method returns an array of JS objects. If we assign them to the data attribute of a call to jQuery.ajax(), that would account for the serialized object parameters I'm seeing on the server. We need to pass an object as the data attribute, not an array of objects?
However, when I try to flatten the array into one object, the whole thing breaks and a HTML request is sent to the server instead of a JS one. I think it has something to do with the fact that jQuery.ajax.processData == false.
I have an issue on the Remotipart Github.
After a ton of debugging and reading through lots of code, I finally have the latest gem working with Rails 3.2.8. I was nailed by three gotchas:
(1) I was disabling my file input field prior to form submission and this causes remotipart to ignore it for inclusion in the iframe submission. You must make sure your file inputs are enabled. This is the direct cause of the bug you are seeing.
(2) In the course of my debugging, I was overriding jquery.iframe-transport with the latest upstream source and it doesn't have support for the X-Http-Accepts hidden variable in the iframe. You must use the version bundled with the remotipart gem.
(3) Don't forget to wire up a callback for ajax:complete on the form if you are using a datatype other than script. This is the default if you don't specify dataType in the global ajax options, or use the data-type attribute on the form.
I am new to Rails but I come from PHP, in which it was almost always the case that whenever I have an HTML AJAX response, I can always load it in a container(any element) using jquery's .load()
I did that with Rails too, but recently came into another approach: use .js.erb files. Use getScript() to a controller action, then the js.erb file will respond to the js (ajax) request, the do the loading in the .js.erb file.
given general.js:
$.getScript(url, function(){});
given index.js.erb:
$('#products').html("<%= escape_javascript(render_cell :products, :index, {:products => #products})%>");
but this appears to be quite repetitive when I can do the loading in general.js! Fire an ajax request to this template that a controller has and load that in a container(I can use jquery .load()'s selector to just select the elements I want, and I can use an application_controller condition to not render the layout):
<ul>
<%= render_cell :products, :index, {:products => #products} %>
</ul>
Is there any way I can make more effective use of .js.erb files in this case?
Note: I had to use the 2nd approach because I am using twitter-bootstrap tabs. I initially used the first approach but I think the 2nd way is more "the Rails way". This is a learning project so why not? XD
I'm working on a ruby-on-rails app that would write XML files for each section on a page. So instead of querying the database every time the user makes a request it would simply call the XML file that corresponds to that page and the javascript will parse the file. On the rails side there will be a content management system. When user is ready to commit all their content changes they will hit the publish file at which point the data which possibly was already saved in the database will now be written to an xml file.
The challenge is that I want all the xml files to live inside a folder in the main project directory called xml_display.
How do I configure the routes.rb to take a request like... myhost.com/display_xml/pagename.xml
and return the static page in rails_project_root/display_xml/pagename.xml
I've looked into High Voltage and it doesn't seem to be the solution I'm looking for.
I hope this sounds interesting to you.
You can just make a controller that redirects to your static files something like the following:
routes.rb
match '/display_xml/:id', :action => 'display'
display_xml_controller.rb
class DisplayXMLController
def display
redirect_to "http://#{host_domain}/static_xml_dir_in_public/#{params[:id]}.xml
end
end
You need to set host_domain to wherever you are running from. Most set up in a config.yml