NoobOnRails

Ruby on Rails tips, tricks and hints for the aspiring rails hero.



Saturday, September 30, 2006

Using Rails to solve real world problems



I am a strong believer in using what's available to right a wrong or to fix something that could be better. If you know how to use the tools, there's no reason what you can't make a change. With that introduction, I introduce the fruition of a few hours work...a little app I call mathcards (screenshot above). You know all that talk about solving real world problems? Well, for me, my problem was a lost my 6 yr old daughter's math cards. Ooops. Hard to raise a world dominator when you can even help her stay sharp in math. So I thought, "flash cards are easy enough to mimic on a web site, why not build a site that can give her basically the same training?". Bam, a few hours later, there's mathcards. It's out and free for the world to use. Use it for your kids, use it because you're a rails newb who needs all the open source app they can get their hands on or just use to tinker with it and expand out the functionality. I remembered hearing about Google release some sort of sourceforge app so I figured this would be a good app to test it out on. The project's main site is here and the source information (including SVN info) is here. Check it out and if anyone is reading this, feel free to let me know what you think :)

Wednesday, September 27, 2006

Good SEO mojo with Rails


So you've created your site that allows you to sell all the cool desinger knitted sweaters you've made over the past few weeks and you've just stuck your site online. Five months later, no one has visited your site outside of you and grandma and she didn't even buy anything. Cheapskate. At this point you realize, to make it big, you have to get some decent ranking on the big search engines.

Now, I'm not going to even pretend like I'm MR. SEO or anything but I'm going to post a few tips that I believe can help, not harm, your page ranking and hopefully give you somewhere to start from. I'll start with three tips, if you can think of anything else, please, feel free to comment below. If you have any requests, put'em up. I can't guarantee I can fulfill them but at least there's a chance it'll spark some interest or conversation. So, here are three basic Ruby on Rails SEO tips:


1. WWW or no WWW

Without any configuration on your server or routes, your website can be accessed two ways, http://yoursite.com and http://www.yoursite.com. Seems harmless but the problem with this is, or so I've heard, that some search engines may consider them as two seperate sites and think that you're duplicating your content, as a means to try and trick them. They tend to frown on this so the quicker you can avoid this, the better.
UPDATE: As the anonymous posted below pointed out, the matt cutts article I had in mind when writing this, doesn't necessarily take this stance. He states that you should basically use redirects as a means to point the search engine's crawlers to the right content. I could've sworn I heard the double content idea from somebody though. Oh well, false alarm.

I believe the best and most effective way to handle this is at the web server level and for me, I'm currently using Mongrel to host my cookmor site (no www's in that link, click it and watch it redirect) so this is how I did this redirect for Mongrel: You first need to create a mongrel.conf file to throw this code in (you'll call it when you start Mongrel, you'll see later) so create a mongrel.conf file and stick it in your railsapp/log/ folder. This goes in the mongrel.conf file:

class RedirectHost <>

def process(request, response)
if request.params["HTTP_X_FORWARDED_HOST"] == "yoursite.com"
response.start(302,true) do head, body
head["Location"] = "http://www.yoursite.com/"
head["Content-type"] = "text/html"
body.write("Please go here instead: http://noobonrails.blogspot.com/")

end
end
end

end

uri "/", :handler => RedirectHost.new, :in_front => true


Once that file is created and saved, stop mongrel. Restart it by using this statement:

mongrel_rails start -e production -p YOURDESIREDPORT -d -S log/mongrel.conf

Booyah. Now chances are you may not be using only mongrel to host your site, and that's ok, so to compensate, here's how you do it with lighttpd, here's how you do it with Apache and even how to do it with LightSpeed. That's all I could think of.


2. Prettier URLs

This really depends on how you define pretty. If you define pretty as http://www.yourbooks.com/books/show/rails-is-fer-heroes, then you're ok. If not, you're will be getting nothing but tumbleweeds my friend. The whole thinking here is that, if the urls are easier for the search engines to read and understand, it will be easier for them to match up keywords to the proper pages on your site. Just don't try to fit too many keywords in your url, I'm sure /show/credit_reporting_for_credit_reporters_reporting_on_credit will look a little suspicious.

So, say you have a book website on which you list your books. You also have a show action in your controller that is called whenever you want to show the details of a certain book. Currently, the url on your show book page looks something like this, http://www.mybooksrox.com/books/show/422. Now that's all fine and dandy but we can do better for Google. Let's create a "named route" in your config/routes.rb file (more on routes here). So above the

map.connect ':controller/:action/:id'


that is the defacto standard route that all routes.rb contain at the onset, stick this route:

map.book 'books/:booktitle', :controller => 'books', :action => 'show'

What this is doing is telling rails to generate a URL of books/whateverbooktitleis when invoked from the books controller and show action. Where do we define booktitle? Where ever we make a call to show a recipe, like this:

<% for book in @books%><li>* %lt;%= link_to book.title, book_url(:booktitle => book.title) %></li>

<% end -%>
This does assume that you have a title column in your books table. book_url is actually calling the named route we created and we're passing the booktitle param along with it. Save your files and on whatever page you created those links on, they should now point to a url which includes the book titles.

3. Google Sitemaps

Now that I've typed this much, I can't really rememebr what number 3 was supposed to be... oh well. The next tip I could think of is to use Google Sitemaps for your site so that Google can easily serach and index it. There's a good, basic article here that seems just fine. For mre information on Google sitemaps and why they're the bees kness, check out their site here.

That's all I could think of for now. If I missed anything, please let me know. Happy coding.

Sunday, September 24, 2006

How to make a Dynamic Sortable List


This one was a but tricky for my noobish rails mind but once I found the solution, it made a lot of sense. Basically, I had this list of items that I needed to be sortable. The problem was, the use could change the contents of this list via an RJS-friendly selection list. When the user did make a change, the list wouldn't be sortable anymore. Why wasn't it sortable anymore you ask? Because my rjs template was only replacing the list container, to showcase the new contents, and not the actual JavaScript that rendered the list sortable. Here's what my selection list looked like:

<%= form_remote_tag :url => {:action => "get_list", :id => @days_out},
:html => {:id => "shopping_list"} %>
<%= select("dinner", "days_out", %w{1 2 3 4 5 6 7}, { :include_blank => true })%>
<%= submit_tag "Get List" %>
<%= end_form_tag %>


and my shopping list container looked like this:




and here's the scriptaculous code that makes my list sortable:

<%= render :partial => 'sort'%>


(the sort partial):

<%= sortable_element 'shop_list', :complete => visual_effect(:highlight, 'shop_list'), :url => { :action => "order" } %>

So I had my selection list form, my list of sortable items and the code to make my list sortable. What does the dynamic updating? Why my RJS template of course. Here's the get_list action in my controller:
def get_list @days_out = params[:dinner][:days_out] @recipes = Dinner.find(:all, :conditions => ["dinner_night between ? and ?", Date.today, Date.today+(@days_out.to_i)], :include => :recipe).map {|r| r.recipe.ingredients} Dinner.parse(@recipes) end

I grab the values that were passed by the form and stick them into the @days_out instance variable. Then I use that value to determine which ingredients I need to populate my selection list with. That "Dinner.parse(@recipes)" just cleans up the ingredients so the user gets a basic list, uncluttered by the (what I've deemed) unnecessary.

Here's the get_list.rjs template:

page.replace_html 'shop_list', :partial => 'item' page.replace_html 'sort', :partial => 'sort' page.visual_effect :highlight, 'shop_list', :duration => 1

As you can see in the rjs template, I first replace the shopping list partial, then I replace the scriptaculous code and then I wrap it up by yellow-fading the whole list. Purty ain't it?

Sunday, September 17, 2006

Railsconf Europe


Sounds like Rails conf Europe was a good couple of days. A few blogs out there have a good coverage of waht went down, but Xml blog and the Copenhagen Ruby Brigade seem to have most of the bases covered as far as content goes. By the look of the flickr photos, it looks like everyone had a good time.

Saturday, September 09, 2006

All the bests Rake tasks


I just came across (just as in the day before yesterday) a site that has a list of all (as far as I know) of the possible rake tasks you can run in the context of your Rails application. From the old fav rake db:schema:dump to the new cool rake db:sessions:clear and even the classic rake rails:freeze:edge. Good resource.


UPDATE: the main site, http://idiotis.ms/, has a lot of cheatsheets for other commands as well, like gem and capistrano.

Saturday, September 02, 2006

error: Association named ...... was not found


After totally reworking one of my apps (have to gut it since I'm changing it's focus), I botted up mongrel, expecting to see everything was hunky dory and working great. I browsed to one of my list actions and I got this error:

Association named 'user' was not found; perhaps you misspelled it?


Hmmm. I know that's how you spell user so I knew that wasn't the problem. What the problem ended up being was I was trying to eagerly load this object's users with a :include => 'user'. This worked in the past because this object's table had a user_id column in it. But, due to me reworking it, it no longer did. So to sum how I resolved this errror, I just removed the

, :include => 'user'


and it worked fine.