Let's dive in!
You can give almost any (maybe any) HTML element an "id" or a "class". An id applies to only one element, and you use the following to apply style to it:
#dog { color:red; }A class applies to all elements with that class, you use this:
.dog { color:red; }You can restrict this to certain types of elements like so:
a.dog { color:red; }
Rails also is currently using the JQuery javascript library. I am sold on this -- you really do want to use some javascript library to abstract away any browser specific issues. (let the JQuery library writers sweat over that ugly nonsense). Note that JQuery is a client side library.
I say they "are currently using" because I know the trends in the rails community to jump from one bandwagon to another (Prototype was the javascript "library of choice" not all that long ago amongst the rails crowd). My 5 year old book (published in 2008), "the Rails Way", boldly proclaims that it is up to date for Rails 2.0, and is now wildly out of date. Sometime in the not too distant future we will be on to something else and all of this will be ridiculously irrelevant and out of date too.
There is all kinds on unclear and worthless documentation on Jquery, here are some vital things to know:
document.getElementbyId("x") -- becomes --> $("x") document.getElementbyTagName("img") -- becomes --> $("img") document.getElementbyClass("x") -- becomes --> $(".x")
It is very common to specify an anonymous function for an event:
$("#mine").click( function () { body; });
To insert a bunch of static html (or whatever) in its place, you would just do:$('#youradhere').load('yourad.html');What I actually did in my mounts.js.coffeescript file was this:$ -> $("#find_location").click -> $("#loadtest").load("/load.html")This grabbed public/load.html and injected it into a div with id "loadtest". Clicking the button repeatedly just replaces the same content. Nice. Note that the load() call can send extra stuff to the server, and can invoke a function when it finishes to do error recovery and such. It has some other tricks too.The jQuery get() function can take a data argument that has stuff it is supposed to pass to the server like so:
$.get("test.php", { name:"Wally", rank:"Private" });jQuery get() and post() with html
These are shortcuts for the more general jQuery.ajax() call and have essentially the same interface.I bind to the same button click used in the load() example above using the following. Note that while this is coffeescript, I wrap a snippet of javascript in backticks to force it down coffeescripts throat. I prefer curly brackets to the insane tab nonsense that coffescript offers.
$ -> $("#find_location").click -> info = $("#mount_location").val() `$.get("/find_loc", { info: info }, function(data) { $('#loadtest').html(data); });`On the server side, I am now bouncing through a rails route and into my controller where I have the following code:def find_loc @loc_info = params[:info] # renders app/views/mounts/find_loc.html.erb respond_to do |format| format.html { render layout: false } format.js end endBy default $.get asks for html. I suppress the layout that all my normal views get (we don't want a layout wrapped around an ajax response). Then the file find_loc.html.erb gets returned more or less verbatim to the browser, and the code there slaps it into the waiting div with id="loadtest".jQuery get() and post() with json
By adding an additional dataType argument to the jQuery.get() call, the flavor of data expected to be returned can be specified. The following example specifies "json". A person could specify "xml" if he was stupid or enjoyed suffering. It is not possible to specify "js".$ -> $("#find_location").click -> info = $("#mount_location").val() `$.get("/find_loc", { info: info }, function(data) { $('body').append("I took a long bit of experimenting to find out that when this is requested, the "data" returned is actually a javascript object, not some kind of string. Very handy, but not documented that I could find. To work with this, the server side was changed to:" + data.name); $("#loadtest").html(data.info) }, "json" );`
def find_loc @loc_info = params[:info] # concocted ruby hash for response reply = { name: "micros", info: @loc_info } respond_to do |format| format.html { render layout: false } format.js { render json: reply } end endThe "render json: reply" instructs that the ruby hash be converted to json to be sent to the client. Apparently jQuery on the client converts this transparently to a javascript object. A lot of handy plumbing.Everything still works if I change format.js to format.json -- so I am unclear on why these both exist (or why format.js exists at all given we are talking entirely about json). It is equally unclear what purpose is served by find_loc.js.erb.
We can change this to an array instead of a hash without any trouble:
$ -> $("#find_location").click -> info = $("#mount_location").val() `$.get("/find_loc", { info: info }, function(data) { var rsp = ''; for (var i = 0; i < data.length; i++) { rsp = rsp + "And on the server side:" + data[i]; } $("#loadtest").html(rsp); }, "json" );`
def find_loc @loc_info = params[:info] reply = [ "micros", "dog", "cat", @loc_info ] respond_to do |format| format.html { render layout: false } format.json { render json: reply } end endUnobtrusive Javascript
Rather than setting up lots of onclick events, the "rails way" is to use what they call "unobtrusive javascript". Consider the following:
<a href="#" onclick="this.style.backgroundColor='#990000'">Paint it red</a>This explicitly calls inline javascript (and could call a javascript function if it wanted to). The trick is to do the following instead:<a href="#" data-background-color="#990000">Paint it red</a>It is possible to set up a "watcher" that takes action when it sees something going on with a attribute that looks like "data-*", the following is suggested, which requires more knowledge of coffeescript and jQuery than I possess so far:paintIt = (element, backgroundColor, textColor) -> element.style.backgroundColor = backgroundColor if textColor? element.style.color = textColor $ -> $("a[data-background-color]").click -> backgroundColor = $(this).data("background-color") textColor = $(this).data("text-color") paintIt(this, backgroundColor, textColor)That explains the idea, but the devil is in the details. Rails will do a lot of this for you, but the details of the plumbing are essentially undocumented. You can grub around and piece things together. If you get lucky, rails will do all the dirty work for you and you just need to insert special magic custom attributes in your html:
On the server side, you do something like this:
def create @user = User.new(params[:user]) respond_to do |format| if @user.save format.html { redirect_to @user, notice: 'User was successfully created.' } format.js {} format.json { render json: @user, status: :created, location: @user } end end end"respond_to" is a controller helper (there is also respond_with). The magic here is that the ajax request includes a mime type that indicates what flavor of response should be returned. Based on this mime type, only one of the three "format" lines gets executed.
Here in the case of format.js the response is generated by rendering the file (for a users controller) app/views/users/create.js.erb.
Ruby on Rails notes / [email protected]