I can't really understand all those jQuery folks. You say it's much better but I can't see why. Prototype has improved A LOT with 1.6 release and is quite nice to use (and definately more nice looking to read).
I haven't heard any arguments why exactly jquery is so superior to prototype...
Holy cow, I was wondering *yesterday evening* when will you release a jQuery railscast, and voilà! Railscasts make Monday mornings enjoyable again :-)
btw. recent statistics, generated from Rails Rumble suggest that jQuery is on the rise, and in fact, among the RR teams it was more popular than Prototype:
UJS for short means, that you don't put you onclick or whatever attributes to tags, but instead call a single function at the end of the page, that attaches events to dom nodes. I.e. with $('id').observe('click', handler) as with Prototype.
Instead of $(this).attr("action") you could do this.action (since "this" is the unadorned element). I tend to do that since while I love jQuery, I think the syntax can get a little busy, especially with attr().
In your custom submitWithAjax() function, you should add a return so you have 'return this.submit...', or add a 'return this' at the end. This ensures you can chain expressions, e.g. $('#foo_form').submitWithAjax().somethingElse();
Oh, and while Ajax submission is a great example, and sometimes you want to implement it yourself for more control, there is of course a plugin for it: http://malsup.com/jquery/form/
Why I personally prefer jQuery over Prototype is mostly that I like unobtrusive JavaScript[1] and that the powerful selectors, event handlers and chaining make it easy to do very cool things with very little code.
I'd say (though there is likely a definition somewhere that differs) that unobtrusive JS is about keeping JS behavior separate from the HTML layer, just as you hopefully keep HTML and CSS distinct.
You do this by attaching events to the DOM when the DOM is ready instead of using onclick etc.
It also encompasses the idea of progressive enhancement, e.g. making a form or link work fine without JavaScript first, then attaching events or modifying the DOM from the JS layer so the experience gets better if you have JS, and still works if you don't.
MTH: http://errtheblog.com/posts/73-the-jskinny-on-jquery (Ryan also linked it above) is a good advocacy article.
Note that you can use jQuery fine without jRails (as Ryan showed in the screencast), and many jQuery users would argue that Rails Prototype helpers/jRails helpers are bad because they produce obtrusive JS. In a sense, there's less reason to switch from to jRails than to just jQuery.
...so setting the accept header will have no effect (unless you re-enable it via use_accept_header) -- you'll need to append the correct format via an extension.
xhr requests, however, default to format.js, so no need to append '.js'
There's a long list of pros and cons with jQuery, more than I could adequately cover in this episode. Here I just wanted to show how to use jQuery, not why.
In general though, if you enjoy working directly with javascript (instead of hiding it behind helper methods and rjs) and being unobtrusive is important to you, then jQuery seems like a good choice.
Ultimately it comes down to whichever you feel comfortable with.
@Pedro, oops, I forgot the jRails link, thanks!
@stijn, unobtrusive javascript means you don't interfere with the existing (working) HTML source by adding javascript inline. Instead you inject all the needed behavior using external javascript files.
@Henrik, thanks for the tips. I'll update the code with your suggestions.
@JQ, AFAIK security is no different than the prototype/rjs method. They are both doing the same thing: submitting an AJAX request and executing the returned javascript.
@Geoff, thanks for pointing that out! Not sure how I missed that commit.
"$(document).ready(function() {" can actually be shortened down to "$(function() {" since the default behavior of $() receiving a function is the same as ready on document.
However, I use "jQuery(function($) {", so that it wont be an issue if something overrides the $ variable - it is passed as an argument to the callback here so you wont be accessing the global variable inside the function body. Note that $ is the same as the "jQuery" variable. If you load jQuery last and need $ to be what it was before, you can also call "jQuery.noConflict();" to restore it.
Also worth noting is that semicolons are not often required, but encouraged.
@derek, no merb cast planned (since I want to stay on topic of Rails), but if there's enough interest then maybe.
@Gruszks, I left off validations to keep things simple and because it didn't flow well. I'm also playing around with a few different ways to handle AJAX validations, so maybe it will be a separate screencast.
I just got done with a project where I used jQuery quite extensively. I find it a lot of fun to use, and easier the Prototype because it “is just selector/whistles-and-dongles (effects) framework.” My one big peace of learning from this project was to limit my use of 'id' in my html as much as possible. It is a real nightmare having to name every element you want to use. The selector in jQuery is much more powerful being a superset of CSS3.
My humble suggestion is to initially skip the id for anything that doesn't need it for CSS. If selection is to complex or ambiguous, first try adding a class to an element. Sense classes are reusable, it makes code reuse simple as adding a class to other elements. Your form for example could have been selected simply as $('form') all forms on a page will then submit with Ajax. If this is not appropriate, try $('#some_div form'). Or maybe add an 'ajax' class to the forms that you want to submit asynchronously.
The need to constantly name every element on a page will eventually drive you up the wall.
i think jquery is holding totally different ideas from Prototype.
jquery aims to maintain a minimal core for dom & ajax , but prototype is kind of ruby-clone on JS.
Wasn't there a problem when using Jquery and CSRF protection ?
Do we still need thos kind of hacks : http://errtheblog.com/posts/73-the-jskinny-on-jquery#comment_1154 ?
Fantastic screencast! Helped me refactor some similar stuff I had been doing with Rails and jQuery. For those who'd like to check out another tutorial on this subject, my blog post:
Is there a way to make the link_to :delete to be less unobtrusive? I really dont like how it generates a full form in place along with the authenticity_token which means i can't cache anything with that link.
One idea is that we put the authenticity_token in the meta tag/or some other suitable non-cached part of the page with an id and use jquery to scan for delete links and handle the click event on those links to make the correct call to the server along with the authenticity token in place. Anyone already worked on something like that?
Very interesting video, as new to rails and new to javascript in general, I was wondering how to make both work together, but couldn't figure it out because of information overload. This screencasts sums it up pretty well, now all I have to do is learn a bit more javascript and jquery.
Great screencast, I am not using jRails for the same reason you mentioned. Jeff, submit(handler) is a shorthand for using bind('submit', handler). Take a look at the "Events" section found here: http://jquery.bassistance.de/api-browser
In my comment earlier (#38), i mistakenly wrote if there was a way to make the link_to :delete "less unobtrusive". What I obviously meant, was to make it "less obtrusive". Oh the vagaries...
Daniel, thanks for the pastie, i'd like to see how your structure your html in the pastie as well. I think you are relying on the fact that there is a edit link around the delete link. How about relying on the href of the delete link itself?
Thank you for this post. I was trying to make this work, but unfortunately the code in the create.js.erb is not being executed. The text in the message form is stored in the database correctly and I assume that the create.js.erb file is found, as I get an error if I delete it. The problem is that the popup alert does not appear.
Please help!
Heads up on a little gotcha that had us scratching our heads since last night.
It seems the js.erb file still generates the file within a layout, which went against my assumptions of the layout being left out, a la rjs.
So if you're getting loads of html returned and you're thinking along the lines of some sort of mime type confusion, have a closer look at what's coming back and stick a render :template => false in your format.js block.
jQuery vs Prototype argument... it really comes down to personal preference. I much, much prefer jQuery due to the far superior documentation of the library compared with prototype. Devs get spoilt with jQuery, it's far too easy when reading the examples.etc. I found with the prototype documentation I still had to piece things together in my head before I could write solutions. That's just my view of it, others may have had a different experience.
I couldn't get this technique to render the create.js.erb with a nested resource. Has anyone had any luck? For example, posting a form with an action like "/users/1/reviews" wasn't executing the returned JS, but posting a form with "/reviews" works fine.
In both cases, the actual controller method is invoked correctly, it's just the response that isn't working the same with a nested resource -- after looking through the code, I'm still not sure what to update.
Just in case anyone runs into the issue I mentioned, if you specify a default layout, the layout will be used with a JS response. In other words, in the example, the format.js option will render the create.js.erb file, but with the HTML from the specified layout.
Seems pretty obvious now, but I assumed if the response was going to be of content-type "text/javascript", it wouldn't try to use an "html.erb" layout in any situation (since embedding javascript directly in HTML doesn't work), and just automagically render create.js.erb with no layout.
as a starter - and slow student - i'm often intrigued to look for the underlying code (and relations) and have it working 'my way.'
maybe you, or one of your readers could help me with the following.
after adjusting and adding the 'screencast code' to my app, there are two reviews submitted to the database... and subsequently returned on the products/show.html.erb screen. any idea how i could solve this would be welcome!
for your thoughts: putting the alert('hello') in the create.js.erb file gives me this friendly message two times.
in my utter despair and after hours trying and erring i turned to you and your readers with the above 70. egorbrandt Feb 11, 2009 at 06:24.
getting bold and bored i simply removed the <%= javascript_include_tag 'jquery', 'application' %> from application.html.erb. your guess is as good as was mine: it worked, and solved my original problem with the two posts (or puts).
why would removing that tag solve my problem? my confusion is even greater right now.
No one has mentioned performance... jquery is a lot more stable and faster in IE and FF. There are performance tests out there and you can see the difference is considerable and worth while if client side performance matters to you. Also the library size is smaller as well.
I noticed that this works only when application.html.erb layout is used. If using something other than that and in your controller saying layout 'some_layout' it will render js.erb in HTML.
Is this a bug or a feature? or am I doing something wrong?
I am using rails 2.2.2
Hi, great tutorial :) love your work ... but it seems i can't get it working.
i have a form i want to submit with ajax but it allways just renders my javascript source. so i added an alert in the 'this.submit' to see if that submit is being used .. and the alert never shows. So i geuss it is never called correctly. When i put an alert in the submitWithAjax it get's called once which is correct and it's the form i need. Any idea what can be wrong ?
I had a bug with this approach on Internet Explorer. My remote form submissions were processed correctly on the server. However, rather than execute the returned callback script I was getting a "Security Error - File Download" and apprised that IE didn't know what to do with a 'text/javascript' file.
If you're fighting this, here's what I did.
In my case I've found out that IE doesn't set the accept headers correctly, so you SHOULD request a file with the right extension (.js, probably). In the railscast, Ryan, you allude to skipping this, and the change @Geoff (comment #16 above) mentions may be involved.
If you're not using one of the ruby remote form doodads, you'll want to not only set jQuery to munge the xhr headers, but also ensure the form is sent to /widget/69.js and not the default /widget/69
You can see the <a href="http://gist.github.com/111459">code snippet I use</a> at http://gist.github.com/111459
It's basically the same as in the railscast, but with the '+ ".js"' amendment in the jQuery.fn.submitWithAjax part
I also adorn the form's submit buttons with a spinner (using a CSS class), but that's just for shine.
As always, thanks a ton Ryan. Your episodes are monumentally helpful.
@Daan -- see if the code at http://gist.github.com/111459 works for you.
If not, install Firefox and the excellent Firebug add-on. Then enable the javascript console -- you can monitor what is sent, what is received, headers, everything. For even better deep inspection install the TamperData plugin -- you can pause and modify data as it enters and leaves the browser.
I am also getting the issues reported by many of the comments - where the results are render as HTML instead of JS.
{ render :layout => false } did not solve my issue.
However, I noticed that *.js.erb is always rendered as HTML. Changing it back to *.js.rjs correctly render it as JS.
I am on rails 2.3.2.
I am running on Rails 2.3.2 as well and getting the error where the server responds in HTML instead of javascript. Brad's solutions above worked for me, though. Hoping to see a more elegant solution to this...
Ryan, thanks for the great coverage of using jQuery with Rails. One question, is there a standard rails way to handle errors when processing ajax requests?
I really liked this railscast. One thing that's left to wonder about is regarding the syntax to instruct rails to render a different javascript file in the respond_to block. I understand the Rails way is to render a file with the same name as the method you're in, but what if I wanted to render a javascript file in a different views folder than that controller with a different filename than that of the method executing the respond_to block?
I have tried many different methods, the one shown here, and other ajax form plugins for jquery, and none of them trigger the JS respond_to block in my controller! The request is sent to the controller in the background, but my create.js file is not activated by the controller. I am runny rails 2.3.3 and jQuery 1.3.1
I really can't put my finger on why it is not activating the respond_to block.....
Hopefully this will help someone out. I had a problem with this not rendering my javascript and just submitting through the format.html. turns out that because I was rendering the form with a button which popped it out, the DOM didnt pick it up in the beginning so I couldnt perform the JS on it. I tried $(#div).live but that doesn't support submit, so I ended up just embedding this code in the partial:
hi, i like your cast. but i have a problem with this episode. i get am 406 not acceptable error from the ajax action and i could not find the fault.
i try to set the mime type in the mime_types.rb. my rails version is 2.3.5
Doesn't having all your application js code in a single file become hard to maintain? Furthermore, this comment related js will be in other views that are unrelated and do not use this code, isn't that an issue as well?
I've been trying to get this working as well. the .js.erb will always get html entity escaping done on it, as if it is a regular html file. The problem is that I am returning the script as content to an iframe to handle file submitions using ajax, and basically the content injected winds up not working.
$("<div>..."); and so on winds up not parsing into dom elements.
Hi I've been working through the 'Creating a weblog in 15 minutes with Rails 2' from http://rubyonrails.org/screencasts.
I then worked through your screencast (changing names as required) that when really well except for the form resetting. I think it's because my form is <% remote_form_for [@contact, Comment.new] do |f| %> and not <% form_for Review.new(:product => @product) do |f| %>.
awesome rails cast, of course. I owe you money Ryan!
one thing that I found though in order for the javascript to actually exocute, using Rails 2.3.5 and jQuery 1.4.2 is that you need to add render layout=> false option to the format.js in the controller, like such:
respond_to do |format|
format.js { render :layout => false }
end
Oh. Great! I am using jQuery for a long time and it is really better then Proto!
Here is jRails project: http://ennerchi.com/projects/jrails
I can't really understand all those jQuery folks. You say it's much better but I can't see why. Prototype has improved A LOT with 1.6 release and is quite nice to use (and definately more nice looking to read).
I haven't heard any arguments why exactly jquery is so superior to prototype...
Holy cow, I was wondering *yesterday evening* when will you release a jQuery railscast, and voilà! Railscasts make Monday mornings enjoyable again :-)
btw. recent statistics, generated from Rails Rumble suggest that jQuery is on the rise, and in fact, among the RR teams it was more popular than Prototype:
http://www.rubyrailways.com/rails-rumble-observations-part-ii-trends-in-gemplugin-usage
Hi Ryan,
thanks for the great screencast!
A lot is talked about Jquery these days but is it worth making the switch? You also mention Unobtrusive javascript. What does it mean?
Especially when jQuery is just selector/whistles-and-dongles (effects) framework, and prototype has classes and inheritance.
I know you can use module pattern (http://yuiblog.com/blog/2007/06/12/module-pattern/) but it still offers no inheritance...
@ stijn goris
UJS for short means, that you don't put you onclick or whatever attributes to tags, but instead call a single function at the end of the page, that attaches events to dom nodes. I.e. with $('id').observe('click', handler) as with Prototype.
Great screencast as always, Ryan.
Some thoughts:
Instead of $(this).attr("action") you could do this.action (since "this" is the unadorned element). I tend to do that since while I love jQuery, I think the syntax can get a little busy, especially with attr().
In your custom submitWithAjax() function, you should add a return so you have 'return this.submit...', or add a 'return this' at the end. This ensures you can chain expressions, e.g. $('#foo_form').submitWithAjax().somethingElse();
Oh, and while Ajax submission is a great example, and sometimes you want to implement it yourself for more control, there is of course a plugin for it: http://malsup.com/jquery/form/
Why I personally prefer jQuery over Prototype is mostly that I like unobtrusive JavaScript[1] and that the powerful selectors, event handlers and chaining make it easy to do very cool things with very little code.
I'd say (though there is likely a definition somewhere that differs) that unobtrusive JS is about keeping JS behavior separate from the HTML layer, just as you hopefully keep HTML and CSS distinct.
You do this by attaching events to the DOM when the DOM is ready instead of using onclick etc.
It also encompasses the idea of progressive enhancement, e.g. making a form or link work fine without JavaScript first, then attaching events or modifying the DOM from the JS layer so the experience gets better if you have JS, and still works if you don't.
It looks complex.
I still didn't see reasons to switch to jRails.
Maybe someone has a link to complete pros & cons article?
MTH: http://errtheblog.com/posts/73-the-jskinny-on-jquery (Ryan also linked it above) is a good advocacy article.
Note that you can use jQuery fine without jRails (as Ryan showed in the screencast), and many jQuery users would argue that Rails Prototype helpers/jRails helpers are bad because they produce obtrusive JS. In a sense, there's less reason to switch from to jRails than to just jQuery.
More jQuery goodness: http://github.com/leethal/sample-rails-apps/tree/master/jquery_and_ajax
Excellent screencast, thanks a bunch
ah...cool.
I just swapped from Prototype to jQuery (in a non-rails project) and it's very good =D
How about security? Doesn't default rjs/proto config makes it harder to post unauthorized data.
Excellent stuff!
Ryan, note that accept header format recognition has been disabled by default:
http://github.com/rails/rails/commit/2f4aaed7b3feb3be787a316fab3144c06bb21a27
...so setting the accept header will have no effect (unless you re-enable it via use_accept_header) -- you'll need to append the correct format via an extension.
xhr requests, however, default to format.js, so no need to append '.js'
There's a long list of pros and cons with jQuery, more than I could adequately cover in this episode. Here I just wanted to show how to use jQuery, not why.
In general though, if you enjoy working directly with javascript (instead of hiding it behind helper methods and rjs) and being unobtrusive is important to you, then jQuery seems like a good choice.
Ultimately it comes down to whichever you feel comfortable with.
@Pedro, oops, I forgot the jRails link, thanks!
@stijn, unobtrusive javascript means you don't interfere with the existing (working) HTML source by adding javascript inline. Instead you inject all the needed behavior using external javascript files.
@Henrik, thanks for the tips. I'll update the code with your suggestions.
@JQ, AFAIK security is no different than the prototype/rjs method. They are both doing the same thing: submitting an AJAX request and executing the returned javascript.
@Geoff, thanks for pointing that out! Not sure how I missed that commit.
thank you for getting to jquery, any idea on when merb will get a cast?
Hi Ryan,
can you please make some validation beafore send request to server?
"$(document).ready(function() {" can actually be shortened down to "$(function() {" since the default behavior of $() receiving a function is the same as ready on document.
However, I use "jQuery(function($) {", so that it wont be an issue if something overrides the $ variable - it is passed as an argument to the callback here so you wont be accessing the global variable inside the function body. Note that $ is the same as the "jQuery" variable. If you load jQuery last and need $ to be what it was before, you can also call "jQuery.noConflict();" to restore it.
Also worth noting is that semicolons are not often required, but encouraged.
@derek, no merb cast planned (since I want to stay on topic of Rails), but if there's enough interest then maybe.
@Gruszks, I left off validations to keep things simple and because it didn't flow well. I'm also playing around with a few different ways to handle AJAX validations, so maybe it will be a separate screencast.
@Dag, thanks for the tips!
I just got done with a project where I used jQuery quite extensively. I find it a lot of fun to use, and easier the Prototype because it “is just selector/whistles-and-dongles (effects) framework.” My one big peace of learning from this project was to limit my use of 'id' in my html as much as possible. It is a real nightmare having to name every element you want to use. The selector in jQuery is much more powerful being a superset of CSS3.
My humble suggestion is to initially skip the id for anything that doesn't need it for CSS. If selection is to complex or ambiguous, first try adding a class to an element. Sense classes are reusable, it makes code reuse simple as adding a class to other elements. Your form for example could have been selected simply as $('form') all forms on a page will then submit with Ajax. If this is not appropriate, try $('#some_div form'). Or maybe add an 'ajax' class to the forms that you want to submit asynchronously.
The need to constantly name every element on a page will eventually drive you up the wall.
i think jquery is holding totally different ideas from Prototype.
jquery aims to maintain a minimal core for dom & ajax , but prototype is kind of ruby-clone on JS.
Ryan, an AJAX validation screencast would be very helpful.
Hi all. Is there some way to keep the prototype working together with jquery?
I would like to migrate to jquery, but I want to do it progressively.
Thanks to the railscast.
Wasn't there a problem when using Jquery and CSRF protection ?
Do we still need thos kind of hacks : http://errtheblog.com/posts/73-the-jskinny-on-jquery#comment_1154 ?
Great screencast by the way ;)
By the way, can you achieve same technique with jQuery?
http://arturaz.net/blog/?p=545
@Ryan, correction on my previous comment -- looks like Accept header recognition was re-enabled with this commit:
http://github.com/rails/rails/commit/4ce9931f4f30045b2975328e7d42a02188e35079
Franco,
just put jQuery.noConflict() in your application.js, and jQuery will relinquish control of the $ method
Fantastic screencast! Helped me refactor some similar stuff I had been doing with Rails and jQuery. For those who'd like to check out another tutorial on this subject, my blog post:
http://polyrails.com/2008/11/11/steps-to-unobtrusive-rails-with-jquery/
Covers AJAX approach leveraging your existing rails templates (eg edit.html.erb) and reporting validation errors w/ jQuery unobtrusive JS.
Is there a way to make the link_to :delete to be less unobtrusive? I really dont like how it generates a full form in place along with the authenticity_token which means i can't cache anything with that link.
One idea is that we put the authenticity_token in the meta tag/or some other suitable non-cached part of the page with an id and use jquery to scan for delete links and handle the click event on those links to make the correct call to the server along with the authenticity token in place. Anyone already worked on something like that?
@Aditya - I had this same exact issue. Here is my solution:
http://pastie.org/320945
(Basically I load the edit form into the page and change _method to 'delete' instead of 'put', and submit :-P)
Ryan - thanks so much! I learned a lot :-)
DanNewman's method looks better - putting the authorization token in the layout header.
Although I'm wondering if that's a security hole?
I created an unobtrusive jQuery screen cast a little while ago inspired by these Railscasts.
http://thenexttrain.co.za/2008/08/screencast-ruby-on-rails-unobtrusive-jquery/
Very interesting video, as new to rails and new to javascript in general, I was wondering how to make both work together, but couldn't figure it out because of information overload. This screencasts sums it up pretty well, now all I have to do is learn a bit more javascript and jquery.
I'm a grateful student of all of this. Please forgive me if I'm wrong, but shouldn't the submitWithAjax portion in application.js read:
this.submit= function() {
and not
this.submit(function() {
?
Isn't the idea to redefine the submit function?
Thanks for your efforts, I've learned alot from them.
Great screencast, I am not using jRails for the same reason you mentioned. Jeff, submit(handler) is a shorthand for using bind('submit', handler). Take a look at the "Events" section found here: http://jquery.bassistance.de/api-browser
In my comment earlier (#38), i mistakenly wrote if there was a way to make the link_to :delete "less unobtrusive". What I obviously meant, was to make it "less obtrusive". Oh the vagaries...
Daniel, thanks for the pastie, i'd like to see how your structure your html in the pastie as well. I think you are relying on the fact that there is a edit link around the delete link. How about relying on the href of the delete link itself?
Thank you for this post. I was trying to make this work, but unfortunately the code in the create.js.erb is not being executed. The text in the message form is stored in the database correctly and I assume that the create.js.erb file is found, as I get an error if I delete it. The problem is that the popup alert does not appear.
Please help!
Heads up on a little gotcha that had us scratching our heads since last night.
It seems the js.erb file still generates the file within a layout, which went against my assumptions of the layout being left out, a la rjs.
So if you're getting loads of html returned and you're thinking along the lines of some sort of mime type confusion, have a closer look at what's coming back and stick a render :template => false in your format.js block.
Cheers,
Jon
Thanks for the screen cast, Ryan.
I have been using a jQuery plugin called Ajax Forms, which I find much more intuitive. ($.ajaxForm)
check it out here:
http://malsup.com/jquery/form/
These screencasts always seem to fit in with what I am doing.
I was working through the jQuery in action book and wanted to use Rails rather than the jsp example. Your screencast was invaluable.
Thanks as ever.
I am looking to get into merb and I hope that the community starts to produce something as valuable as this.
jQuery vs Prototype argument... it really comes down to personal preference. I much, much prefer jQuery due to the far superior documentation of the library compared with prototype. Devs get spoilt with jQuery, it's far too easy when reading the examples.etc. I found with the prototype documentation I still had to piece things together in my head before I could write solutions. That's just my view of it, others may have had a different experience.
fantastic screencast ryan! thanks for this and all the others.
I couldn't get this technique to render the create.js.erb with a nested resource. Has anyone had any luck? For example, posting a form with an action like "/users/1/reviews" wasn't executing the returned JS, but posting a form with "/reviews" works fine.
In both cases, the actual controller method is invoked correctly, it's just the response that isn't working the same with a nested resource -- after looking through the code, I'm still not sure what to update.
Just in case anyone runs into the issue I mentioned, if you specify a default layout, the layout will be used with a JS response. In other words, in the example, the format.js option will render the create.js.erb file, but with the HTML from the specified layout.
Seems pretty obvious now, but I assumed if the response was going to be of content-type "text/javascript", it wouldn't try to use an "html.erb" layout in any situation (since embedding javascript directly in HTML doesn't work), and just automagically render create.js.erb with no layout.
Hi Ryan!
Nice cast as usual. Thanks!
But when I start to follow it I found that it could be done a little bit simpler.
What about set of methods like remote_form_for? (another really useful method is link_to_remote)
http://apidock.com/rails/ActionView/Helpers/PrototypeHelper/remote_form_for
jRails supports them as well. And you can keep application.js clear this way.
Another minor recommendation from jRails site regarding layouts/application.html.erb:
you can write just <%= javascript_include_tag :defaults %>
your screencasts are great.
as a starter - and slow student - i'm often intrigued to look for the underlying code (and relations) and have it working 'my way.'
maybe you, or one of your readers could help me with the following.
after adjusting and adding the 'screencast code' to my app, there are two reviews submitted to the database... and subsequently returned on the products/show.html.erb screen. any idea how i could solve this would be welcome!
for your thoughts: putting the alert('hello') in the create.js.erb file gives me this friendly message two times.
thanks again, egorbrandt
in my utter despair and after hours trying and erring i turned to you and your readers with the above 70. egorbrandt Feb 11, 2009 at 06:24.
getting bold and bored i simply removed the <%= javascript_include_tag 'jquery', 'application' %> from application.html.erb. your guess is as good as was mine: it worked, and solved my original problem with the two posts (or puts).
why would removing that tag solve my problem? my confusion is even greater right now.
Hey Ryan,
Awesome! Just one question. How come you put the javascript that handles the form submit in application.js and not directly in the view?
No one has mentioned performance... jquery is a lot more stable and faster in IE and FF. There are performance tests out there and you can see the difference is considerable and worth while if client side performance matters to you. Also the library size is smaller as well.
@egorbrandt It was probably being called from a partial as well? I had the same issue.
i am running into the problem mentioned above in comment #49. My response is being rendered in HTML per the default layout. How do you stop that?
that is my response is being returned as HTML with the js code embedded.
I noticed that this works only when application.html.erb layout is used. If using something other than that and in your controller saying layout 'some_layout' it will render js.erb in HTML.
Is this a bug or a feature? or am I doing something wrong?
I am using rails 2.2.2
I am having the same issues with the js.erb template being rendered within an HTML layout.
The only 2 solutions I have found so far have been
doing:
format.js { render :layout => false }
every time in the controller OR doing this in the application controller:
layout proc { |controller| controller.request.xhr? ? nil : 'my_html_layout' }
I am hoping there is a better solution.
Yet another option in application controller:
exempt_from_layout /\.js\.erb$/
just for note. I did get this to work in 2.3.2
Check for misspellings!
Found no better place for it: Thanks a lot for your excellent site! I'm just starting with rails and your screencasts are a great help.
Is the Download link working? To me it fails, "Safari can't connect to the server".
Hi, great tutorial :) love your work ... but it seems i can't get it working.
i have a form i want to submit with ajax but it allways just renders my javascript source. so i added an alert in the 'this.submit' to see if that submit is being used .. and the alert never shows. So i geuss it is never called correctly. When i put an alert in the submitWithAjax it get's called once which is correct and it's the form i need. Any idea what can be wrong ?
greets,
Daan
I had a bug with this approach on Internet Explorer. My remote form submissions were processed correctly on the server. However, rather than execute the returned callback script I was getting a "Security Error - File Download" and apprised that IE didn't know what to do with a 'text/javascript' file.
If you're fighting this, here's what I did.
In my case I've found out that IE doesn't set the accept headers correctly, so you SHOULD request a file with the right extension (.js, probably). In the railscast, Ryan, you allude to skipping this, and the change @Geoff (comment #16 above) mentions may be involved.
If you're not using one of the ruby remote form doodads, you'll want to not only set jQuery to munge the xhr headers, but also ensure the form is sent to /widget/69.js and not the default /widget/69
You can see the <a href="http://gist.github.com/111459">code snippet I use</a> at http://gist.github.com/111459
It's basically the same as in the railscast, but with the '+ ".js"' amendment in the jQuery.fn.submitWithAjax part
I also adorn the form's submit buttons with a spinner (using a CSS class), but that's just for shine.
As always, thanks a ton Ryan. Your episodes are monumentally helpful.
@Daan -- see if the code at http://gist.github.com/111459 works for you.
If not, install Firefox and the excellent Firebug add-on. Then enable the javascript console -- you can monitor what is sent, what is received, headers, everything. For even better deep inspection install the TamperData plugin -- you can pause and modify data as it enters and leaves the browser.
I am also getting the issues reported by many of the comments - where the results are render as HTML instead of JS.
{ render :layout => false } did not solve my issue.
However, I noticed that *.js.erb is always rendered as HTML. Changing it back to *.js.rjs correctly render it as JS.
I am on rails 2.3.2.
Update: looks like this is a bug in rails. Which is/being fixed:
https://rails.lighthouseapp.com/projects/8994/tickets/2022-jserb-templates-broken-in-230-rc1
I am running on Rails 2.3.2 as well and getting the error where the server responds in HTML instead of javascript. Brad's solutions above worked for me, though. Hoping to see a more elegant solution to this...
Ryan, thanks for the great coverage of using jQuery with Rails. One question, is there a standard rails way to handle errors when processing ajax requests?
I really liked this railscast. One thing that's left to wonder about is regarding the syntax to instruct rails to render a different javascript file in the respond_to block. I understand the Rails way is to render a file with the same name as the method you're in, but what if I wanted to render a javascript file in a different views folder than that controller with a different filename than that of the method executing the respond_to block?
Wow, just fought a strange bug -- this is a real gotcha. If you are using the ":disable_with" option -- like this ...
<%= f.submit "Create review", :disable_with => translate('general.disable_with') %>
-- then the form will post as standard html. That took about an hour to find. Hope it didn't get you too.
These are interesting techniques. I have two problems with them though.
The create template's name ends with .erb although all the code in it is Javascript. That's confusing.
The JQuery.ajaxSetup method makes all forms of the application into Ajax forms. It's not flexible enough.
I have tried many different methods, the one shown here, and other ajax form plugins for jquery, and none of them trigger the JS respond_to block in my controller! The request is sent to the controller in the background, but my create.js file is not activated by the controller. I am runny rails 2.3.3 and jQuery 1.3.1
I really can't put my finger on why it is not activating the respond_to block.....
Just a note that I found with rails 2.3.4. The flash_notice div is not getting updated when the next review is submitted. I changed
$("#new_review").before("<div id=\"flash_notice\"><%= escape_javascript(flash.delete(:notice)) %></div>");
to:
$("#flash_notice").html('<%=escape_javascript(flash.delete(:notice)) %>');
the jrails site is a dead link : http://ennerchi.com/projects/jrails
Hopefully this will help someone out. I had a problem with this not rendering my javascript and just submitting through the format.html. turns out that because I was rendering the form with a button which popped it out, the DOM didnt pick it up in the beginning so I couldnt perform the JS on it. I tried $(#div).live but that doesn't support submit, so I ended up just embedding this code in the partial:
jQuery.ajaxSetup({
'beforeSend': function(xhr) {xhr.setRequestHeader("Accept", "text/javascript")}
})
jQuery.fn.submitWithAjax = function() {
this.submit(function() {
$.post(this.action, $(this).serialize(), null, "script");
return false;
})
return this;
};
$(document).ready(function() {
$("#new_review").submitWithAjax();
})
Then it works fine!
Thanks Ryan, I didn't realize it was so easy to use webrat on its own!
@ Brad S
Thank you! Thank you! After 12 hours trying to render the js files without the html the only think worked was your suggestion to add
exempt_from_layout /\.js\.erb$/
to the application controller!
Thanks a lot
hi, i like your cast. but i have a problem with this episode. i get am 406 not acceptable error from the ajax action and i could not find the fault.
i try to set the mime type in the mime_types.rb. my rails version is 2.3.5
adding text/javascript to /etc/mime.types solve the problem.
Doesn't having all your application js code in a single file become hard to maintain? Furthermore, this comment related js will be in other views that are unrelated and do not use this code, isn't that an issue as well?
I've been trying to get this working as well. the .js.erb will always get html entity escaping done on it, as if it is a regular html file. The problem is that I am returning the script as content to an iframe to handle file submitions using ajax, and basically the content injected winds up not working.
$("<div>..."); and so on winds up not parsing into dom elements.
thank you for this, its helps me alot...
i got one question, how will i apply it to multiple forms in one page?
thanks!
Will Rails 3 have this functionality out of the box? For example, when I do script/generate scaffolding, will it create AJAX scaffolding too?
If you are getting a message:
uninitialized constant ApplicationController
then rename application.rb to application_controller.rb
Hi I've been working through the 'Creating a weblog in 15 minutes with Rails 2' from http://rubyonrails.org/screencasts.
I then worked through your screencast (changing names as required) that when really well except for the form resetting. I think it's because my form is <% remote_form_for [@contact, Comment.new] do |f| %> and not <% form_for Review.new(:product => @product) do |f| %>.
any tips?
I want to update the value of my form with the .keyup() function from jQuery. So every change in the form updates the database.
What I have to change in the code to get it run?
$.ajaxSetup({
'beforeSend': function(xhr) {xhr.setRequestHeader("Accept", "text/javascript")}
})
$.fn.submitWithAjax = function() {
this.submit(function() {
$.post(this.action, $(this).serialize(), null, "script");
return false;
})
return this;
}
$(document).ready(function() {
$(".summary_points").keyup(function(){
$(this).submitWithAjax();
})
})
awesome rails cast, of course. I owe you money Ryan!
one thing that I found though in order for the javascript to actually exocute, using Rails 2.3.5 and jQuery 1.4.2 is that you need to add render layout=> false option to the format.js in the controller, like such:
respond_to do |format|
format.js { render :layout => false }
end
Slight change to make it work on exiting a field see my mods on stackoverflow: http://stackoverflow.com/questions/1795979/strange-jquery-post-problem-wrong-post-url-is-used/5953359#5953359
Does this lesson work in rails 3 as is, or are there some modifications to do? I can't seem to make my included javascript files to work
Because when I look in my document head I have
the application.js showing
But when I open the firebug script console the application.js isn't available or showing