@Tony, the "new" action is really there, it's just not shown in the controller. There's a "new.rhtml" view which will be used for the new action. That just displays the login form. The "create" action handles the login process which is what the form goes to.
Really dumb question from a total noob, I'm sure: The routing action is shown as "new," but the action is shown in the SessionsController as "create." What am I not understanding?
@Diego, yep. You can create a model object which doesn't inherit from ActiveRecord and just use that. However, validation will be quite a bit trickier.
Even if you don't need to store the data in the database, I prefer to anyway. This way I have a backup of every user input in case the email isn't delivered properly.
@Wes, are you asking where the "approved?" method comes from? This is generated automatically by Rails. Since there's a boolean "approved" attribute in the database, it gives us the "approved?" method which will return true/false.
There's also a class method called "approved" which just does a find for all comments which are approved. I use this for listing the comments for each episode. It's completely separate from the "approved?" instance method.
I like to think of the exclamation mark as a warning that the method does something potentially dangerous/permanent. This way you think twice before using it and make sure that's really what you want.
Here I'm using it because the method is contacting Akismet in addition to changing the model's state. This method shouldn't be called lightly.
IIRC, the exclamation is just a character and does not specifically modify the behavior of any method. It has become common in the Rails framework to denote that the method does something different (as mutle noted) as opposed to a method without it. And thus many people have adopted it's use.
Same as the equals in a method name. It doesn't really change the behavior of the method, but when creating getter/setter methods it makes you code more clear. Hence for the setter you can write 'mysetter=myvalue' instead of 'mysetter myvalue'.
Nice screencast. This is something I definitely need to do on a few of my sites. I've used Akismet before with PHP but never implemented it with rails yet.
If I'm not mistaken, the exclamation mark at the end of methods means that you are modifying a variable instead of just accessing it. For example, "foobar.sort" will return a sorted array, but leave foobar alone. "foobar.sort!" will actually replace foobar with the sorted array.
By adding an exclamation mark to the end of the method like that he's just noting that the method is changing a class variable. It's optional, but good practice.
There is also a Ruby on Rails Akismet project on Ruby Forge from Josh French. Josh French said by the README, "This plugin is based on David Czarnecki's Akismet.rb (http://www.blojsom.com/blog/david/nerdery/2005/12/02/Akismet-API-in-Ruby.html) found via Soaked and Soaped (http://sas.sparklingstudios.com/articles/2006/10/01/how-to-protect-a-rails-application-against-spam-with-akismet)"
I've always thought the frequency and quality of the content was fantastic. I really appreciate all the work you've put into Railscasts, an excellent resource.
Just watched this again and noticed something curious.. what does an exclamation point do to an method? You have this one your mark_as_spam/ham actions.
Great stuff, Ryan.
Unfortunately Akismet is pretty pricey, if you want to use it commercially. I am working for a Blog-Host, and using Akismet would cost double of what we pay for server hosting.
But what I have seen in your screencast seems like it may be worth the money. Currently we have a custom CAPTCHA, which works fine for now, except that you can't user CAPTCHAs for Trackbacks.
Anyway, thanks for this plugin, I will try it out.
I was wondering if anybody could tell me the best way to avoid duplicates with a has many through relationship. I basically want a pair of ids to be unique in the database...
I had to laugh at the comments about one a week. I discovered railscasts this morning and I've just watched all 64! It's been a fantastic way to spend a rainy Saturday. Keep up the good work!
@Javan, at first I tried using Dreamhost's DNS but had some trouble with it, so right now I'm using Slicehost's DNS and pointing media.railscasts.com and mail.railscasts.com back to Dreamhost. Feel free to email me if you want more details.
I am in agreement with others that one a week won't satisfy my need for your railscasts but can appreciate the time needed to make and edit them, perhaps now that your only doing one a week they can be a little longer? Anyway, thanks for the great content you have already provided
I completely understand only doing 1 per week -- personally, I would like 10 per week! You're doing a great job...
As a future screencast request, maybe sometime you could explain method_missing and show one or two clever ways it can be used? Just a thought... Keep up the good work!
I trying the "after_add and after_remove" way.But I met a problem.
I can successfully update the counter cache when adding or destroying the associated record.But how about the updating?
Any tips,thx?
I just got into railscasts, so this move to 1 a week is even more shocking to me. Until recently, I was able to watch one new 'cast a day, but now that I'm caught up, one a week seems like an even bigger shock to most. Anyway, great work! I look forward to future "lessons" no matter how infrequent.
Every model needs an auto-incrementing id column in Rails, so I recommend remaking a "categorizations" table and not trying to use the legacy categories_products table.
@zzeroo, thanks, fixed the error. As for your problem, I'm not sure what it could be. Is the due_at column a datetime type? Is it considered a Time object by Ruby? Try playing with it in script/console and repeating the error.
I would suggest Ryan do one per week but make them much longer.
And/Or, do a 1-2 HOUR screen cast on a really detailed subject and sell them. But that would compete with Peepcode. Maybe he could sell them through Peepcode.
cbmeeks
http://www.signaldev.com
<< is for adding.
How about removing the association?
When calling @product.categorizations.delete, nothing happened.
if calling @production.categorizations.clear
it gave a sql error some thing like " DELETE FROM categories_products WHERE `id` = NULL".(Because I use the legacy habtm table without autoincrement id )
Don't worry, Railscasts isn't going anywhere. I may still do three a week once and a while when I have the time, just don't count on it being a regular occurrence. This will give me some more time to catch up on the other things I've been putting off.
Thanks Ryan! Your info helps a lot. As for having one model spanning multiple tables, it is something I will not commit, even though it can be done, just because of "serious hacking" as you say. The :include option sounds perfect, however! Thanks again.
@RainChen, right, this is one reason you may want to stick with habtm. Some methods like "product_ids=" are not available so you'll have to create them manually if you need them.
Normally, to update the association you either create or update the join model itself. Such as "categoirzation.new" or "categorization.update_attributes". You can also use the "<<" method to create the join. See this for details:
Hmm, not entirely sure what you're asking, but eithe way it should work without any changes. See this pastie code for an example of passing a string to the block.
Every Monday, Wednesday, and Friday I made it a ritual to get up first thing in the morning, load Google Reader, and excite myself seeing 'Railscasts (1)'. Unfortunately, that ritual can only happen on Monday now. With this happening, and the fact that Mr. Peepcode is releasing screencasts in shorter "parts" now to get more money, I can't help but feel the Rails community is dying. Please resurrect it. You are our savior.
Ryan, thanks so much - I'm glad you're doing 1 a week now (though I'd happily still watch and absorb 3), but it's a helluvalotof work.. If you ever decide to make full length screencasts, I'm sure people would be interested.
@Tony, the "new" action is really there, it's just not shown in the controller. There's a "new.rhtml" view which will be used for the new action. That just displays the login form. The "create" action handles the login process which is what the form goes to.
Really dumb question from a total noob, I'm sure: The routing action is shown as "new," but the action is shown in the SessionsController as "create." What am I not understanding?
BTW, Ryan, you totally rock.
@Diego, yep. You can create a model object which doesn't inherit from ActiveRecord and just use that. However, validation will be quite a bit trickier.
Even if you don't need to store the data in the database, I prefer to anyway. This way I have a backup of every user input in case the email isn't delivered properly.
is there a way to avoid the database part, i just want to send the mail directly without saving the mail into the database, is there a way to do this?
@Wes, are you asking where the "approved?" method comes from? This is generated automatically by Rails. Since there's a boolean "approved" attribute in the database, it gives us the "approved?" method which will return true/false.
There's also a class method called "approved" which just does a find for all comments which are approved. I use this for listing the comments for each episode. It's completely separate from the "approved?" instance method.
Did you add an index for comments.approved? Just curious.
Just to note, methods ending in ? typically return true or false. Again, it's convention, not a requirement. It just makes it easier to read.
@bob, nope. If you have an array of projects you'll have to fetch the tasks for all those projects using a custom find of some sort.
@Wincent, that's already done. If you look in the controller on the screencast you can see there's an "authorize" before filter.
will this work if you have @projects, i.e multiple projects?
Ryan, shouldn't you have some kind of "is_admin?" before filter protecting your destroy_multiple/approve/reject actions?
@jeff, you can avoid duplicates by using the validates_uniqueness_of method. You'll likely need to use the :scope option to include the other columns.
I like to think of the exclamation mark as a warning that the method does something potentially dangerous/permanent. This way you think twice before using it and make sure that's really what you want.
Here I'm using it because the method is contacting Akismet in addition to changing the model's state. This method shouldn't be called lightly.
IIRC, the exclamation is just a character and does not specifically modify the behavior of any method. It has become common in the Rails framework to denote that the method does something different (as mutle noted) as opposed to a method without it. And thus many people have adopted it's use.
Same as the equals in a method name. It doesn't really change the behavior of the method, but when creating getter/setter methods it makes you code more clear. Hence for the setter you can write 'mysetter=myvalue' instead of 'mysetter myvalue'.
Thanks for that concise explanation Saxon!
My Rails-fu went up a few points
In ActiveRecord methods the exclamation mark is used to tell that it raises an exception if something goes wrong (like save!, create!).
I recommend using defensio. It's smarter than Akismet and learns as it goes. It also has a much better API for developers.
Check it out: http://www.defensio.com/
Nice screencast. This is something I definitely need to do on a few of my sites. I've used Akismet before with PHP but never implemented it with rails yet.
If I'm not mistaken, the exclamation mark at the end of methods means that you are modifying a variable instead of just accessing it. For example, "foobar.sort" will return a sorted array, but leave foobar alone. "foobar.sort!" will actually replace foobar with the sorted array.
By adding an exclamation mark to the end of the method like that he's just noting that the method is changing a class variable. It's optional, but good practice.
There is also a Ruby on Rails Akismet project on Ruby Forge from Josh French. Josh French said by the README, "This plugin is based on David Czarnecki's Akismet.rb (http://www.blojsom.com/blog/david/nerdery/2005/12/02/Akismet-API-in-Ruby.html) found via Soaked and Soaped (http://sas.sparklingstudios.com/articles/2006/10/01/how-to-protect-a-rails-application-against-spam-with-akismet)"
I've always thought the frequency and quality of the content was fantastic. I really appreciate all the work you've put into Railscasts, an excellent resource.
Just watched this again and noticed something curious.. what does an exclamation point do to an method? You have this one your mark_as_spam/ham actions.
*injects cable modem needle into arm*
Ahhhhhh...yeah that's the stuff.
*stays high on Rails for hours*
Great stuff, Ryan.
Unfortunately Akismet is pretty pricey, if you want to use it commercially. I am working for a Blog-Host, and using Akismet would cost double of what we pay for server hosting.
But what I have seen in your screencast seems like it may be worth the money. Currently we have a custom CAPTCHA, which works fine for now, except that you can't user CAPTCHAs for Trackbacks.
Anyway, thanks for this plugin, I will try it out.
gaert!vrey good.
tkanhs
Great tutorial thought, I've already sent mail from script/console :)
Keep up the great work!
Oops, just forgot the UserMailer is the class that I've created and that inherits from ActionMailer.
what is the difference with ActionMailer and UserMailer?
is there a way to send email from script/console directly?
I was wondering if anybody could tell me the best way to avoid duplicates with a has many through relationship. I basically want a pair of ids to be unique in the database...
thanks in advance
I had to laugh at the comments about one a week. I discovered railscasts this morning and I've just watched all 64! It's been a fantastic way to spend a rainy Saturday. Keep up the good work!
@Javan, at first I tried using Dreamhost's DNS but had some trouble with it, so right now I'm using Slicehost's DNS and pointing media.railscasts.com and mail.railscasts.com back to Dreamhost. Feel free to email me if you want more details.
Ryan, thank you for all the railscasts! I always enjoy watching, and Ihave learned a ton.
I'm curious about your slicehost/dreamhost config. Do you use dreamhost's DNS and just point web traffic this way? Or??
I am in agreement with others that one a week won't satisfy my need for your railscasts but can appreciate the time needed to make and edit them, perhaps now that your only doing one a week they can be a little longer? Anyway, thanks for the great content you have already provided
I completely understand only doing 1 per week -- personally, I would like 10 per week! You're doing a great job...
As a future screencast request, maybe sometime you could explain method_missing and show one or two clever ways it can be used? Just a thought... Keep up the good work!
I trying the "after_add and after_remove" way.But I met a problem.
I can successfully update the counter cache when adding or destroying the associated record.But how about the updating?
Any tips,thx?
I just got into railscasts, so this move to 1 a week is even more shocking to me. Until recently, I was able to watch one new 'cast a day, but now that I'm caught up, one a week seems like an even bigger shock to most. Anyway, great work! I look forward to future "lessons" no matter how infrequent.
So it seems not so easy to change to use has_many :through.
How about the has_many_polymorphs plugin?
It is said that it could saves lives ^0^
Every model needs an auto-incrementing id column in Rails, so I recommend remaking a "categorizations" table and not trying to use the legacy categories_products table.
@zzeroo, thanks, fixed the error. As for your problem, I'm not sure what it could be. Is the due_at column a datetime type? Is it considered a Time object by Ruby? Try playing with it in script/console and repeating the error.
Great screen cast.
I would suggest Ryan do one per week but make them much longer.
And/Or, do a 1-2 HOUR screen cast on a really detailed subject and sell them. But that would compete with Peepcode. Maybe he could sell them through Peepcode.
cbmeeks
http://www.signaldev.com
<< is for adding.
How about removing the association?
When calling @product.categorizations.delete, nothing happened.
if calling @production.categorizations.clear
it gave a sql error some thing like " DELETE FROM categories_products WHERE `id` = NULL".(Because I use the legacy habtm table without autoincrement id )
so how to deal with this case?
Hi@all,
I think theres an error in the code snippets above.
<!-- tasks/_form.rhtml -->
<%= f.text_field :due_at %>
must bee
<!-- tasks/_form.rhtml -->
<%= f.text_field :due_at_string %>
or isn't it.
Secondly ever time when I use
# models/task.rb
def due_at_string
due_at.to_s(:db)
end
I run in an ugly :
ArgumentError in Overtimes#new
wrong number of arguments (1 for 0)
with...
# models/task.rb
def due_at_string
due_at
end
... in my Models this happens not. Can Somebody explain me that?
Sweet. That's exactly what I needed I didn't know you could pass an argument to capture
Don't worry, Railscasts isn't going anywhere. I may still do three a week once and a while when I have the time, just don't count on it being a regular occurrence. This will give me some more time to catch up on the other things I've been putting off.
I really enjoy watching the RailsCasts. They teach me -a RoR-beginner- a lot. Keep up the good work, even it's "only" once a week.
Thanks Ryan! Your info helps a lot. As for having one model spanning multiple tables, it is something I will not commit, even though it can be done, just because of "serious hacking" as you say. The :include option sounds perfect, however! Thanks again.
@RainChen, right, this is one reason you may want to stick with habtm. Some methods like "product_ids=" are not available so you'll have to create them manually if you need them.
Normally, to update the association you either create or update the join model itself. Such as "categoirzation.new" or "categorization.update_attributes". You can also use the "<<" method to create the join. See this for details:
http://blog.hasmanythrough.com/2006/8/19/magic-join-model-creation
Hmm, not entirely sure what you're asking, but eithe way it should work without any changes. See this pastie code for an example of passing a string to the block.
http://pastie.caboo.se/84044
Every Monday, Wednesday, and Friday I made it a ritual to get up first thing in the morning, load Google Reader, and excite myself seeing 'Railscasts (1)'. Unfortunately, that ritual can only happen on Monday now. With this happening, and the fact that Mr. Peepcode is releasing screencasts in shorter "parts" now to get more money, I can't help but feel the Rails community is dying. Please resurrect it. You are our savior.
Ryan, thanks so much - I'm glad you're doing 1 a week now (though I'd happily still watch and absorb 3), but it's a helluvalotof work.. If you ever decide to make full length screencasts, I'm sure people would be interested.
great stuff, thanks as always.