def find_by_date
@posts = blog.posts.by_year(params[:year])
if params[:month]
@posts = @posts.by_month(params[:month])
@posts = @posts.by_day(params[:day]) if params[:day]
end
end
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.
...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'
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.
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.
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/
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.
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:
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...
never mind, i found my answer after doing a lot of digging around. i just researched on client-side RJS programming and conditional RJS. (whew!! totally little to no experience with these at all, so figuring it out by myself really meant something.)
if anyone would like to see how i did it, just reply/comment :)
I have learned so much and enjoyed every Railscast I have watched. Thank you for being so kick ass Ryan Bates!
Also on this particular article thank you Peter Hollows for the layout advice. I had the layout not found problem, so I make an empty layout then I was getting some XML element not found error. Your solution solved my problem.
This is fits my scenario perfectly. I did run into a problem in using this with Capistrano however. I get daemon buildup over time. Every time I do a "cap deploy" I end up with a few more daemons running around.
While I think the way you have structured this test is very interesting in that it covers many possible implementations for saving an object to the DB using ActiveRecord; I think there is a pitfall to this method in that you are relying/depending on the underlying platform's implementation, which you as a developer have no control over.
While there may be a small chance of the Rails implementation changing any time soon, you still have no control over this (unless you are one of the Rails developers of course :) ).
Also, I feel that writing tests in the way that has been demonstrated here, while very clever, is simply more difficult, both to write and to read. It seems like you could easily spend more time trying to figure out clever ways to write tests with very high coverage "areas", which would take away from the task of getting your app tested and implemented the specific way you want.
Also, as for readability, this test requires a deeper knowledge of the Rails framework to understand. When someone new comes in to look at the test and underlying implementation, they will see the use of the "valid?" function in the test, but yet will not find this method called anywhere in the implementation. If this person is not already familiar with how ActiveRecord is implemented, then they may have to start going through Rails docs just to make sense of the test code.
While this method for high test coverage is certainly clever, and I thought it was a great screencast, I also feel it has some serious drawbacks.
Is there any way to get the name of the zone DateTime object is in that is in the format used by 'in_time_zone'?
I want to do datetime1.in_time_zone(datetime2.zone) but zone method returns the name in a different format.
I would have thought this to be trivial, but I've been banging my head for hours and can't find a clean way to convert one DateTime to another DateTime's zone.
Ultimately, I want to compare two DateTimes after taking the time zone into account. A normal comparison doesn't seem to do it: start_date_time < 1.hours.from_now doesn't work if the user is in a different time zone from the server.
Sorry for asking, but when I run script/plugin install git://github.com/thoughtbot/paperclip.git on windows I only get information: removing: D:/testy/vendor/plugins/paperclip/.git
What should I do to install plugin from git on windows?
But the only way I can do it is by manually adding the username prefix to my *local* copy of Rakefile and regenerating the gem via the "rake install" task.
The Rakefile would then be restored to its original state before running the "rake build_gemspec" task and committing it to git.
@Laurent, good question, I prefer to only use dependencies where I have a "require" statement which loads that gem. Here there is no "require 'activerecord'" line because I expect the developer to load this environment how he desires. He may have edge rails frozen, in that case ActiveRecord is not loaded from a gem and there's really no gem dependency.
If I had other gem dependencies outside of Rails then I would likely add those.
@Cassiano, it's important the Rakefile be in the git repository so anyone else who clones/forks the repo can regenerate the gem after making changes.
Also the gem name should not contain your username prefix as GitHub will add this when it generates the gem using your gemspec.
Great episode! I set up Paperclip on my local machine (Leopard, running Passenger) and after commenting out the "rescue" in Paperclip::Attachment#post_process, I get this crappy "/tmp/stream.3916.0 is not recognized by the 'identify' command" error.
I have my ImageMagick path set correctly and proper permissions. What gives?
hey all,
i try to get this working but it looks like i can't call the Worker from my controller. if i put a logger.info("TEST") in the worker i don't get a output. any ideas ?
Clarifying my previous post: after generating the gem, if you install it locally by running "gem install pkg\<gem-name>-<version>.gem", you end up with a distinct folder name in "...\ruby\lib\ruby\gems\1.8\gems" when compared to installing it from the git repository (as github always seems to add an owner prefix to the gem name provided in .gemspec file).
But of course adding the owner prefix yourself doesn't solve the issue, as github will still add the owner prefix to whatever gem name you supply to it.
Hey there. I'm following this tutorial (I thought) to the T, but when I try to log in to my app, I get redirected to /sessions/ with the following error:
Unknown action
No action responded to index
Maybe a problem with my routes? I have set up the routes as described here.
1) How do I enforce that this db:populate only gets ran on 'test' environment? Don't want to accidently do it on prod :)
2) What about test scripts that rely on data to be the same, is there a better way of writing tests that don't rely on the data itself in the db? (ie: selenium tests for UI)
Your plugin has a clear (hard) dependency on ActiveRecord. But you do not declare anything in your gem. Can you do that with echoe ? (so uniquify cannot be installed unless activerecord is already installed on the host). Do you recommend to explicit dependencies in gems ?
If you want to get all results, just call #search without any arguments. If you want fuzzy matching using *'s, check out Ryan Heneise's link in comment 38.
@David, there already is spam protection in place behind the scenes which has been working really well (it's blocking an amazing amount of spam). As far as I can tell, the spam you were seeing (now deleted) was from an actual human and not a spam bot.
Yet the /login causes the partial views/sessions/new.html.erb to be displayed. I think it is because of the map.connect(s), but both have /:id, which makes me think there may be another mechanism
i m changing my project search from ferret to thinking sphinx, as ferret gives all data against * , thinking sphinx is not working for *,and how OR condition is handle is thinking sphinx. kindly give me solution.
Thanks for this great screencast. After seeing it, some might want to go to this short tuto I wrote. It explains why git is so useful and how to use it along with github and an open source project:
http://harryseldon.thinkosphere.com/2008/11/08/grand-gardening-with-git
Hi Ryan,
can you please make some validation beafore send request to server?
thank you for getting to jquery, any idea on when merb will get a cast?
Thank you
For all who are interested, this is what I did:
In the controller:
def find_by_date
@posts = blog.posts.by_year(params[:year])
if params[:month]
@posts = @posts.by_month(params[:month])
@posts = @posts.by_day(params[:day]) if params[:day]
end
end
=================
In the model:
named_scope :by_year, lambda { |year| {:conditions => ["YEAR(created_at) = ?", year]} }
named_scope :by_month, lambda { |month| {:conditions => ["MONTH(created_at) = ?", month]} }
named_scope :by_day, lambda { |day| {:conditions => ["DAY(created_at) = ?", day]} }
=================
I'd like to move more of the code into the model, I just haven't thought of a good way yet.
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.
Hi,
Thanks for the tutorial.
Played around with ActionMailer and I got it to work from the console and by running script/server.
We're running passenger (mod_rails) and I can't seem to send mail with it. I'm sending via smtp.
Any suggestions?
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'
How about security? Doesn't default rjs/proto config makes it harder to post unauthorized data.
How to add counter_cache if I have has_many_polymorphs?
For example:
I have model Topic and Articles:
in Topic
has_many_polymorphs :affiliateds,
:from => [:topics, :articles],
:through => :affiliations,
:dependent => :destroy,
:as => :affiliate
How to add topics_count, articles_count?
ah...cool.
I just swapped from Prototype to jQuery (in a non-rails project) and it's very good =D
Excellent screencast, thanks a bunch
More jQuery goodness: http://github.com/leethal/sample-rails-apps/tree/master/jquery_and_ajax
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.
It looks complex.
I still didn't see reasons to switch to jRails.
Maybe someone has a link to complete pros & cons article?
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.
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/
@ 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.
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...
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?
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
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...
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
never mind, i found my answer after doing a lot of digging around. i just researched on client-side RJS programming and conditional RJS. (whew!! totally little to no experience with these at all, so figuring it out by myself really meant something.)
if anyone would like to see how i did it, just reply/comment :)
Hey Ryan, or anyone for that matter who still sees this,
Any idea how to set a limit on the number of row of fields you can "Add more"?
I have learned so much and enjoyed every Railscast I have watched. Thank you for being so kick ass Ryan Bates!
Also on this particular article thank you Peter Hollows for the layout advice. I had the layout not found problem, so I make an empty layout then I was getting some XML element not found error. Your solution solved my problem.
This is fits my scenario perfectly. I did run into a problem in using this with Capistrano however. I get daemon buildup over time. Every time I do a "cap deploy" I end up with a few more daemons running around.
Any idea why this might be happening?
http://pastie.org/316048
Thanks for the great screencast.
While I think the way you have structured this test is very interesting in that it covers many possible implementations for saving an object to the DB using ActiveRecord; I think there is a pitfall to this method in that you are relying/depending on the underlying platform's implementation, which you as a developer have no control over.
While there may be a small chance of the Rails implementation changing any time soon, you still have no control over this (unless you are one of the Rails developers of course :) ).
Also, I feel that writing tests in the way that has been demonstrated here, while very clever, is simply more difficult, both to write and to read. It seems like you could easily spend more time trying to figure out clever ways to write tests with very high coverage "areas", which would take away from the task of getting your app tested and implemented the specific way you want.
Also, as for readability, this test requires a deeper knowledge of the Rails framework to understand. When someone new comes in to look at the test and underlying implementation, they will see the use of the "valid?" function in the test, but yet will not find this method called anywhere in the implementation. If this person is not already familiar with how ActiveRecord is implemented, then they may have to start going through Rails docs just to make sense of the test code.
While this method for high test coverage is certainly clever, and I thought it was a great screencast, I also feel it has some serious drawbacks.
Is there any way to get the name of the zone DateTime object is in that is in the format used by 'in_time_zone'?
I want to do datetime1.in_time_zone(datetime2.zone) but zone method returns the name in a different format.
I would have thought this to be trivial, but I've been banging my head for hours and can't find a clean way to convert one DateTime to another DateTime's zone.
Ultimately, I want to compare two DateTimes after taking the time zone into account. A normal comparison doesn't seem to do it: start_date_time < 1.hours.from_now doesn't work if the user is in a different time zone from the server.
Sorry for asking, but when I run script/plugin install git://github.com/thoughtbot/paperclip.git on windows I only get information: removing: D:/testy/vendor/plugins/paperclip/.git
What should I do to install plugin from git on windows?
I would be nice with an explanation of how Rails know to filter password_confirmation?
@Ryan,
Thanks for the Rakefile explanation.
Regarding the naming problem, my intent is to have a local gem that installs exactly the same as the remote (gihub's) one, such that running:
gem install pkg\ryanb-uniquify-0.1.0.gem
or
gem install ryanb-uniquify --source http://gems.github.com
would yield the same installation.
But the only way I can do it is by manually adding the username prefix to my *local* copy of Rakefile and regenerating the gem via the "rake install" task.
The Rakefile would then be restored to its original state before running the "rake build_gemspec" task and committing it to git.
@Laurent, good question, I prefer to only use dependencies where I have a "require" statement which loads that gem. Here there is no "require 'activerecord'" line because I expect the developer to load this environment how he desires. He may have edge rails frozen, in that case ActiveRecord is not loaded from a gem and there's really no gem dependency.
If I had other gem dependencies outside of Rails then I would likely add those.
@Cassiano, it's important the Rakefile be in the git repository so anyone else who clones/forks the repo can regenerate the gem after making changes.
Also the gem name should not contain your username prefix as GitHub will add this when it generates the gem using your gemspec.
Good cast! Thanks.
Great episode! I set up Paperclip on my local machine (Leopard, running Passenger) and after commenting out the "rescue" in Paperclip::Attachment#post_process, I get this crappy "/tmp/stream.3916.0 is not recognized by the 'identify' command" error.
I have my ImageMagick path set correctly and proper permissions. What gives?
hey all,
i try to get this working but it looks like i can't call the Worker from my controller. if i put a logger.info("TEST") in the worker i don't get a output. any ideas ?
regards + thx for your good work !
Clarifying my previous post: after generating the gem, if you install it locally by running "gem install pkg\<gem-name>-<version>.gem", you end up with a distinct folder name in "...\ruby\lib\ruby\gems\1.8\gems" when compared to installing it from the git repository (as github always seems to add an owner prefix to the gem name provided in .gemspec file).
But of course adding the owner prefix yourself doesn't solve the issue, as github will still add the owner prefix to whatever gem name you supply to it.
Hey there. I'm following this tutorial (I thought) to the T, but when I try to log in to my app, I get redirected to /sessions/ with the following error:
Unknown action
No action responded to index
Maybe a problem with my routes? I have set up the routes as described here.
Can anyone help me out?
For whatever reason, I get a TON of failures during testing phase:
$ rake db:populate
Ftest
F
Finished in 0.872049 seconds.
1) Failure:
test_should_create_directory(ThingControllerTest)
[/usr/lib/ruby/gems/1.8/gems/activesupport-
... about 100 failures form this pint.
Getting wrong number of arguments error, environment.rb:13
Two questions:
1) How do I enforce that this db:populate only gets ran on 'test' environment? Don't want to accidently do it on prod :)
2) What about test scripts that rely on data to be the same, is there a better way of writing tests that don't rely on the data itself in the db? (ie: selenium tests for UI)
Look at the multistage plugin for capistrano, it will work nicely with additional environments.
Is there a way to get populator to add records to a HABTM relationship?
@Ryan,
Thanks for this very useful screencast.
Should Rakefile really be uploaded to github, as it seems like it wont' be used by either github or the final user of the gem?
Shouldn't your gem be named "ryanb-uniquify" instead, as this will be the final folder in "ruby\lib\ruby\gems\1.8\gems" (plus version, of course)?
Ryan. Thx for your great screencasts.
Your plugin has a clear (hard) dependency on ActiveRecord. But you do not declare anything in your gem. Can you do that with echoe ? (so uniquify cannot be installed unless activerecord is already installed on the host). Do you recommend to explicit dependencies in gems ?
Hi Faisal
If you want to get all results, just call #search without any arguments. If you want fuzzy matching using *'s, check out Ryan Heneise's link in comment 38.
@David, there already is spam protection in place behind the scenes which has been working really well (it's blocking an amazing amount of spam). As far as I can tell, the spam you were seeing (now deleted) was from an actual human and not a spam bot.
A follow up question on your @Ryan Bates answer to @Tony #28.
"... The "new" action is really there, it's just not shown in the controller. ..."
# The SessionsController has
def create
...
end
def destroy
...
end
# But does not have a 'new' action
# def new
# ...
# end
# The routes.rb has
map.login 'login', :controlller => 'sessions', :action => 'new'
Yet the /login causes the partial views/sessions/new.html.erb to be displayed. I think it is because of the map.connect(s), but both have /:id, which makes me think there may be another mechanism
i m changing my project search from ferret to thinking sphinx, as ferret gives all data against * , thinking sphinx is not working for *,and how OR condition is handle is thinking sphinx. kindly give me solution.
Thanks for this great screencast. After seeing it, some might want to go to this short tuto I wrote. It explains why git is so useful and how to use it along with github and an open source project:
http://harryseldon.thinkosphere.com/2008/11/08/grand-gardening-with-git
(My name contains the active link)
Great episode.
Greetings from Paraguay.