Monthly Archives: April 2008

Google AdWords for small business

Google and its child

As a search engine, Google’s primary purpose is to locate and organize that little thing known as the internet. Acting as the intermediary between information and the end-user, such as yourself, Google allows users to enter a search query and click search.

Google returns a multitude of resuslts: web pages, files, websites, images; these results are displayed on the left side of the page. Unlike other search engines, Google doesn’t accept pamyent to place websites higher in the search results.  However, Google does allow advertisers to purchase an AdWords ads which appear in parallel with unpaid results.

Why AdWords?

Each month over 80% of Internet users in the US view AdWords Ads…and this doesn’t even include the hundreds of millions of additional worldwide users! AdWords allows you to create simple, effective ads to display to people who are already looking for something related to your business. Gone are the days of irrelevant banner ads, Google has ushered in a new era of keyword-based advertising.

Let’s say you’re looking for some baseball tickets to the Mariner’s game, you’d likely search for "mariners tickets." In addition to search results, Google would display ads on top of and to the right of your search results. Say you’re buying media against the keyword "mariners tickets", you could be advertising directly towards individuals already looking for your products!

If this excites you, check this out…just recently, AdWords has branched out from solely internet advertisting to print, radio, TV, image, video and mobile ads.

 

But I only offer local products or services!

Great! It’s a common misconception that just because you offer local services and don’t ship products, you won’t see a benefit from an AdWords campaign. AdWords allows you you to target ads to specific geographic locations. If you were buying keywords for your massage business, users searching for "seattle flower shops" would see your ads, but users searching for "portland flower shops" would not. Not only will you appear on Google’s search pages, if selected, you would be eligible to appear on Google maps (maps.google.com) and any other sites that have opted into Google’s search network.


I don’t have a large budget to burn

One of the beauties of AdWords is the complete and total control it offers. You can run a media campaign without any minimum spending requirement. You set your budget, and AdWords works with you. By selecting different advertising models you control whether you pay for actual clicks, known as cost-per-click (CPC); or whether you pay for actual ad views, known as cost-per-thousand impressions (CPM).

You can run a successful campaign for $10 a day!

 

In closing

AdWords offers businesses an avenue to reach an audience that is highly relevant, and highly receptive. There’s no way I can cover all the features in a quick article. If you’re interested in pursuing an AdWords campign, feel free to do poke around at the Google AdWords site or send me an email.

RESTful design and the HTTP request

One of the biggest changes in Rails 2.0 is the way the framework pimps RESTful design.

??!@#$%^&*??

My thoughts exactly. Understanding what REST was/did/accomplsiehd was a bit of a struggle for me, hopefully, I can do a good job of breaking the concept down into tasty, digestible portions.

Disclaimer:
If you’re a robotic code monkey like myself, my over-simplified terminology may anger you. By all means, if I am incorrect, which I often am…correct me…but please…think of the kids! Don’t nitpick, it’s just not cool.

The HTTP Request

Before I can explain what REST is, you need to have a basic understand of how your web browser communicates with web servers. Let’s start with something you are familiar with. When you visited my blog, this is what happened:

  1. You typed in www.jonathanng.com

  2. Your browser sent a request to the server

  3. My server responded with HTML

  4. Your browser rendered that HTML

Well…beneath all this seemingly simple transaction, a few more, albeit important things are occurring. Using the same example as above, this is what is really happening:

  1. You typed in www.jonathanng.com

  2. Your browser sent a request to the server (called an HTTP request)

  3. My server responded to that HTTP request

  4. Your browser rendered the HTML that was returned

A HTTP request is like a little sticky note that is passed on to the web server. When the web server gets this note, it can read over the note and determine what action it needs to take place. There are eight different kinds of HTTP requests.

There are two kinds of requests that you should be most comfortable with. The “GET” request and the “POST” request. The “GET” request does exactly what it states, it gets the content of some resource from the server, identified by the URL Working with HTML, it should come as no surprise that the “POST” request is used to send (or POST) data to a URL, eventually creating a new resource.

Resources

I hate to use technical jargon, but some things can’t be side-stepped. Okay, take a deep breath and clear your mind. Stop thinking of the internet as “web pages”, from now on when you’re in Rails land, you need to think of the internet as a “resource.”

You might be a little bit confused, because as I’m writing this, I’m trying to think of a good example. Okay.

Let’s say you click through my site…the about résumé, my portfolio, and about me page. Web pages right? Wrong. These are resources! Take my résumé for example; if I printed it out on paper and handed it to you, it’d still contain everything you’d see if you would have accessed it on the web…but now it’s on paper! What if I took a screen capture and saved it as a JPG; or how about an Adobe PDF? Do you see where I’m going with this?

The “web page” you accessed was just one way to format the resource, in this case, my résumé.

The OTHER HTTP requests

Stick with me for a little while longer. Earlier, I mentioned there were eight types of HTTP requests, well here are all of the HTTP requests:

  1. HEAD
  2. GET
  3. POST
  4. PUT
  5. DELETE
  6. TRACE
  7. OPTIONS
  8. CONNECT

All I want is for you to be aware of these request types, I’m sure you already guess what a few of these do, but don’t freak out if you have no idea.

Let’s tie it all together

Let’s use our Bookstore application as an example. Now, what if I were to tell you this URL could do two different things:

  • http://localhost:3000/books/1

Say what? Do you remember what I said about HTTP requests?

Okay…imagine this…say you want to view book #1, when you click the above URL you are sending a HTTP “GET” request to the server; once the server gets your HTTP request it responds with the information you requested, in this case the title and description for book #1.

Well, after reading over the description I’ve decided book #1 sucks. I want to delete it. If you mouse over the “Destroy” URL for the bookstore app, you’ll notice the URL is as follows:

  • http://localhost:3000/books/1

Hey wait…that’s the same URL as the “Show” link! You are 100% correct. So how can one URL serve multiple purposes? You guessed it, the HTTP request!

When you click the “Destroy” link, you’re sending a HTTP “DELETE” request to the web server. When the web server gets your request it sees you want to DELETE book #1.

Crazy.

Take some time to let this all soak in, it’s actually quite important. You’ll see just how important this RESTful design is when we start digging into our Bookstore application.

You may have noticed I haven’t explained what REST actually stands for, honestly, I have no idea, does it really matter….probably not, but if you’re particularly curious, Wikipedia has the no-nonsense low down on everything we’ve discussed and then some.

I think this is a good point to take a break, not to mention it’s 11PM and I want to play Call of Duty 4. Recently, I added my blog to feedburner, if you want an instant update when I add a new post, subscribe! As usual, leave me a comment for better or worse…if you’re feeling like a badass you can even Digg this or donate to my beer fund!

Until next time folks….

The next tutorial has been published: Rails’ Relationships

Alexa Updates Website Ranking Methodology

Alexa recently released news that they have “better rankings,” and “improved methodology” and have moved past using their Alexa Toolbar as one of the main sources for its rankings. I have always called Alexa the CEO’s site meter tool as the toolbar itself wasn’t even available for MACs. I think every CEO or marketing manager has installed the toolbar at one point in time to check their ranking and it has been used widely by marketing professionals as a research tool for competitive intelligence.

Alexa Ratings

I haven’t used the site or toolbar in over a year and for comparative site reporting I usually frequent sites like Compete.com and Quantcast.com which the industry and website owners have implemented and are using in great numbers to report on their own demographics and to share information to their vertical or category for ranking. These two services have free features and provide pretty detailed information for general comparison reporting or trending. If you have the cash to pay for yearly access to Hitwise, comScore or Nielsen’s net ratings then let me know so you can run a few reports for me too. Those subscriptions are costly and I haven’t seen much value in them unless you are in an interesting vertical and are looking for websites to advertise on that you might not have realized were in your demographic.

I wish sites like 100Hot.com still existed and MediaMetrix still published their top 100 website report online for free. I think I’ll give Alexa another try and see if they are delivering something worthwhile now.

Basic Rail’s routing and a journey into Views, and Controllers

Basic Rail’s routing and a journey into the controller

Thanks for tuning in! Last time we spoke, we set up a basic Rails application called the bookstore. Using the new 2.0 scaffolding, we were able to quickly, and effortlessly move from a high-level thought process to a living, breathing model. Now that you’ve toyed around with the application source, I’m going to explain our codevious code and I’ll even throw a little wrench into your gears…basic Rail’s routing.

Open up your bookstore application, if you’ve lost it or found this post randomly…be sure to visit the original post “Ruby on Rails Tutorial, now with more 2.0.2!“. Then, fire up your server, and navigate to your application’s root, likely, http:/localhost:3000. If your code is untouched from the last time we met, you should encounter a “routing error” like so:

02_routing.jpg

That’s kind of annoying, and just a little bit ugy; it’s time we fix this! You may remember play with .htaccess and doing a mod_rewrite here and there, when you use the Rails framework you no longer place the burden of URL rewriting on the webserver, but instead, on Rails. Routes can get really complicated, really fast; so I am going to show you the very basics. Even after I show you how to play around with Rails’ routing, I will leave the application’s default routes alone. I will do this because in teaching, it is much easier explaining to you that:

http://localhost:3000/books/1

is calling on the “books” controller, with the “show” method, and an “id” of 1 verues trying to explain to you that,

http://localhost:3000/library/freakonomics

can do the exact same thing! All in time though, all in time. Anyways, open up theconfig/routes.rb file and you should see something like this:

Routes are listed in order of priority, the higher on the list they are, the higher priority they are. You’ll notice Rails’ default routes on the bottom:

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

Briefly, when a visitor types in the URL:

http://localhost:3000/books/1

Rails takes the HTTP request, looks through the routes listing, and systematically tries to find a match. With the URL above, the HTTP request will be matched to the first request and processed as follows:

http://localhost:3000/:controller/:action/:id

Hopefully this makes sense, I’ll touch more on this down the road. If you’re not entirely lost, recall that the reason we’re poking around the routes file is because we are getting a routing error when we attempt to access “http://localhost:3000″. At the end of the routes.rb file, add the following:

map.root :controller => "books", :action => "index"

“map.root” is the shorthand to name the root path “”; now whenever we navigate to the site’s root path we should see a call to the “books” controller and “index” action. Take note, you do not have to specificy the “index” action, as it is called by default, but I included it for sake of illustration. Navigate to your site’s root, and watch the magic.

Pretty neat, huh? Add a few more books, and then take some time to examine the URL structure of the database items you’ve entered. When you’ve done that, open up the “apps/models/book.rb” file. The file you just opened is our “Book model”, it acts as the gateway between any database queries. Right now it is empty, but it is worth pointing out. Now open the, “apps/controllers/books_controller.rb” file, you will see first entry is the index method.

  # GET /books
  # GET /books.xml
  def index
    @books = Book.find(:all)

    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @books }
    end
  end

Since this code was generated by Rails, we have a few lines of commenting. What this means is, any GET request to /books will actaully call the “index” method (we’ll talk about the different request types later). When this method is called in, there are two things that happen.

  1. We are talking to our “Book model” and asking it to find all records, then we are saving those results as a Ruby hash in “@books”
  2. Next, depending on the requested format, responding with either an HTML template or XML template (more on this later)

For those readers who have some database expereince, check this out, if this doesn’t make sense, don’t worry.

    # ask the Book model to find :all records
    @books = Book.find(:all)

    # the resulting MySQL query
    SELECT * FROM books

Now, scroll down to the next method…it should be named “show”.

  # GET /books/1
  # GET /books/1.xml
  def show
    @book = Book.find(params[:id])

    respond_to do |format|
      format.html # show.html.erb
      format.xml  { render :xml => @book }
    end
  end

This time, instead asking the Book model to find :all records, we’re asking it to find by the “params[:id]“. What does “params[:id]” mean? The “id” parameter from the URL is accessed by “params[:id]” and in this case, the value is “1″. If we were to type the URL, “http://localhost:3000/books/5″, params[:id] would be set to “5″. Let’s look at this line of code:

@book = Book.find(params[:id])

What we’re doing is assigning the results of our database query, in this case, by asking the Book model to find the record with ID matching params[:id]. You’ll notice that all models are titleized and singular: in this case Book, but it could easily be Author or Category.

Now that you’ve seen how we are retrieving our data from the database, let me show you how to format that data for your visitors. Open your “app/views/books/index.html.erb” file. And you should see this:

If you’ve developed websites in the past, the show view should be a little more familar to you. You will notice a few things that look out of place, with PHP we enclosed our code with the <? code ?> tags, with Ruby, anything enclosed between <% code %> , <%= code %>, is called embedded ruby. Here are the differences:

  • <% code %> is evaluted, but not printed
  • <%= code %> is evaulated, and printed

Check this:

# this will display NOTHING in your HTML
<% "You will not see this" %>

# this will print the string
<%= "But you will see this!" %>

You can test the code by pasting the embedded ruby code, just below the “<h1>Listing Books</h1>” tag, and accessing your site’s root, like so:

See how that works? Now, the final piece of the puzzle!

<% for book in @books %>
<tr>
<td><%=h book.title %></td>
<td><%=h book.description %></td>
<td><%= link_to 'Show', book %></td>
<td><%= link_to 'Edit', edit_book_path(book) %></td>
<td><%= link_to 'Destroy', book, :confirm => 'Are you sure?', :method => :delete %></td>
</tr>

<% end %>

What we’re doing here, is looping through each item in the @books hash, and for each item we are printing out the book title, “book.title” and book description, “book.description”. The “h” you see codeceeding the book title and description is the Rails “HTML escape”. If you type <%= book.title %> instead of <%=h book.title %>, the book title will still dispaly, BUT it is good habit to ALWAYS HTML escape database fields with data that may contain something harmful…read: malicious users entering something other than a book description.

Take a look at the code again, if I were to read it out loud to you it would read as follows:

“For each book in the @books variable, do the following: Print the title; description; and the show, edit, and destroy commands”. To expand on the whole “for” block, here’s another example…if you were feeling rather rebelious, you could do this too:

<% for item in @books %>
<tr>
<td><%=h item.title %></td>
<td><%=h item.description %></td>
<td><%= link_to 'Show', item %></td>
<td><%= link_to 'Edit', edit_book_path(item) %></td>
<td><%= link_to 'Destroy', item, :confirm => 'Are you sure?', :method => :delete %></td>
</tr>

<% end %>

Hopefully that makes some more sense :) As always, if this was this helpful, if you have questions, or if you just want to bullshit…leave me a comment…help me, help you! Feel like donating to my beer fund?

The next part of our journey through Rails covers RESTful design, an integral part of a properly designed and correctly executed Rails web application.

PHP vs Rails

I was milling over some old PHP code today, funny, because my friend Norm linked me to David Hansson’s blog post…it looks like PHP is a Friday thing!

After looking at my old code, I thought to myself, hmm, what better time to showcase the beauty of Rails. I made a post on a message board I frequent, and there was quite a bit of discussion. Anyways, take a look at this!

header("Content-type: text/html; charset=utf-8");
include_once('inc.functions.php');
require('inc.drawrating.php');

$uid = $_GET['uid'];

$conn= mysql_connect("localhost","db","dbpassword") or die (mysql_error());
mysql_select_db(ave_development) or die(mysql_error());


$q = "SELECT views FROM stores WHERE uid=$uid";
$result = mysql_query($q,$conn);
$tmp = mysql_fetch_object($result);
$views = $tmp->views;
$views++;

$lview = date("Y-m-d H:i:s");
$q = "UPDATE stores SET views=$views, last_view='$lview' WHERE uid=$uid";
mysql_query($q, $conn);

$q = "select * from stores where uid = $uid";
$result = mysql_query($q,$conn);
$row = mysql_fetch_object($result);

$name = $row->name;
$phone = $row->phone;

if ($phone == 0) { $phone = ""; } else { $phone = " - " . format_phone($phone); }

$description = $row->description;
$description_lb = str_replace("\n", "<br>", $row->description);

$address = $row->address1;

This is the code I would use if I were to do the same thing in Rails.

# the controller
class StoresController < ApplicationController
 @store = Store.find_by_id(params[:id])
 @store.increment!("views")
end
# I'd place this in my 'show' view
<%= number_to_phone(@store.phone) if @store.phone.exists? -%>
<%= simple_format(@store.description) -%>

Ruby on Rails Tutorial, now with more 2.0.2!

My first Rails application was the ONLamp: Rolling with Ruby on Rails tutorial, since then Rails has come a long way but I find the beginner resources lacking still. The one thing I’ve learned along the way has been that sample code is invaluable, so today, in celebration of my company’s launch of our completely free online dating (and completely Rails) site Meeta.com, I offer codesent to you my version of the Rolling with Ruby on Rails tutorial on OSX.

As always, I am not a Rails genius, so my code may not be perfect; if I’ve done something wrong or there is a better, more Railsesque method please let me know. If you find this useful, leave me a comment, I like to know who is dropping in.

Enough of that. Let’s go!

Let’s start by creating our Rails application, if you’re looking for a tutorial on installing Rails check out the Rails wiki on installation.

From your command prompt, type the command “rails bookstore”. By default, Rails will use SQLite as the default database, if you want to use MySQL you will need to run “rails -d mysql bookstore”. This will create a “bookstore” subdirectory contanting a complete tree of folders and files for your Rails application. This is what you should see:

ng:Sites admin$ rails bookstore
      create
      create  app/controllers
      create  app/helpers
      create  app/models
      create  app/views/layouts
      create  config/environments
      create  config/initializers
      create  db
      create  doc
      create  lib
      create  lib/tasks
      create  log
      create  public/images
      create  public/javascripts
      create  public/stylesheets
      create  script/performance
      create  script/process
      create  test/fixtures
      create  test/functional
      create  test/integration
      create  test/mocks/development
      create  test/mocks/test
      create  test/unit
      create  vendor
      create  vendor/plugins
      create  tmp/sessions
      create  tmp/sockets
      create  tmp/cache
      create  tmp/pids
      create  Rakefile
      create  README
      create  app/controllers/application.rb
      create  app/helpers/application_helper.rb
      create  test/test_helper.rb
      create  config/database.yml
      create  config/routes.rb
      create  public/.htaccess
      create  config/initializers/inflections.rb
      create  config/initializers/mime_types.rb
      create  config/boot.rb
      create  config/environment.rb
      create  config/environments/production.rb
      create  config/environments/development.rb
      create  config/environments/test.rb
      create  script/about
      create  script/console
      create  script/destroy
      create  script/generate
      create  script/performance/benchmarker
      create  script/performance/profiler
      create  script/performance/request
      create  script/process/reaper
      create  script/process/spawner
      create  script/process/inspector
      create  script/runner
      create  script/server
      create  script/plugin
      create  public/dispatch.rb
      create  public/dispatch.cgi
      create  public/dispatch.fcgi
      create  public/404.html
      create  public/422.html
      create  public/500.html
      create  public/index.html
      create  public/favicon.ico
      create  public/robots.txt
      create  public/images/rails.png
      create  public/javascripts/prototype.js
      create  public/javascripts/effects.js
      create  public/javascripts/dragdrop.js
      create  public/javascripts/controls.js
      create  public/javascripts/application.js
      create  doc/README_FOR_APP
      create  log/server.log
      create  log/production.log
      create  log/development.log
      create  log/test.log
ng:Sites admin$

That’s a whole lot of files! I’m not going to get into details about the directory structure because I’m going to write another blog post about this next time. Very briefly, the bulk of the structure is as follows:

  • app contains your application’s models, views, and controllers…the backbone of your app
  • app/controllers contains all your controllers, these guys handle web requests
  • app/helpers contains helper classes, these will help you clean up code allowing you to keep MVC (model, view, controller) code simple and neat
  • app/models contains all your models, models are the gatekeepers to your database
  • app/views contains all your views, these are display templates we will use to plug in data, which in turn is converted to the final HTML pages your users will see
  • public holds all your publicily accessible files, think public_html

I bet you’re excited already…I was! Let’s fire up the server and see what’s going on. Run, “script/server”

ng:bookstore admin$ script/server
=&gt; Booting Mongrel (use 'script/server webrick' to force WEBrick)
=&gt; Rails application starting on http://0.0.0.0:3000
=&gt; Call with -d to detach
=&gt; Ctrl-C to shutdown server
** Ruby version is up-to-date; cgi_multipart_eof_fix was not loaded
** Starting Mongrel listening at 0.0.0.0:3000
** Starting Rails with development environment...
** Rails loaded.
** Loading any Rails specific GemPlugins
** Signals ready.  TERM =&gt; stop.  USR2 =&gt; restart.  INT =&gt; stop (no restart).
** Rails signals registered.  HUP =&gt; reload (without restart).  It might not work well.
** Mongrel available at 0.0.0.0:3000
** Use CTRL-C to stop.

Now, depending how your hosts are set up, visit your application in your browser:

  • http://0.0.0.0:3000
  • http://localhost:3000
  • http:/127.0.0.1:3000

You should see the default Rails placeholder that looks like this:

01_welcome.jpg

You’ll notice this corresponds with the “public/index.html” file. Well, that’s not too exciting…let’s move on to creating your application. Delete the “index.html” file in your “public” directory, then shut down the web-server, and let’s really play ball.

Let’s think about a bookstore at a high level, and how they really work. A bookstore contains books with titles andthese books each belong to categories or genres. This is the foundation of our application. I’m going to show you how to create a working model, then I’ll explain it. By running the following command, you will create a scaffold for the books in your bookstore with a title and description. Run: “script/generate scaffold Book title:string description:text”

ng:bookstore admin$ script/generate scaffold Book title:string description:text
      exists  app/models/
      exists  app/controllers/
      exists  app/helpers/
      create  app/views/books
      exists  app/views/layouts/
      exists  test/functional/
      exists  test/unit/
      create  app/views/books/index.html.erb
      create  app/views/books/show.html.erb
      create  app/views/books/new.html.erb
      create  app/views/books/edit.html.erb
      create  app/views/layouts/books.html.erb
      create  public/stylesheets/scaffold.css
  dependency  model
      exists    app/models/
      exists    test/unit/
      exists    test/fixtures/
      create    app/models/book.rb
      create    test/unit/book_test.rb
      create    test/fixtures/books.yml
      create    db/migrate
      create    db/migrate/001_create_books.rb
      create  app/controllers/books_controller.rb
      create  test/functional/books_controller_test.rb
      create  app/helpers/books_helper.rb
       route  map.resources :books
ng:bookstore admin$

Okay, cool, but what is a scaffold? Think of buidings, when builders are working on a new building they put up scaffolds. This allows them to quickly build their building. As their project nears completion, they tear down the scaffolds. When you ran the “script/generate scaffold Book title:string description:text” command you asked Rails to create a scaffold for you. It provides you with a model, the necessary views, and a controller. These scaffolds allow you to quicky and rapidly develop an application, but should not be relied on in a production environment.

Let’s break down the command: “script/generate scaffold Book title:string description:text”

What you’ve done here is created a scaffold for your books, notice though the command says “Book”. ALL models in Rails are singular while views and controllers are plural. This was one of the points that confused me when I started using Rails, so pay attention! You’ll notice “title:string” and “description:text”, these are the corresponding field names and column types, even cooler is that Rails will automagically determine that your “string” is a VARCHAR or your text is TEXT. I used the examples title and description, because they are simple. These could have easily been “quantity:integer” or “isbn:string”.

Now that we’ve created a scaffold with a working model, views, and controller we need to physically create the database. Let’s do this now by running “rake db:migrate”

ng:bookstore admin$ rake db:migrate
(in /Users/admin/Sites/bookstore)
== 1 CreateBooks: migrating ===================================================
-- create_table(:books)
   -&gt; 0.0035s
== 1 CreateBooks: migrated (0.0038s) ==========================================

ng:bookstore admin$

By running this command, you’ve asked rails to “migrate” your database using the “migrations” located in “db/migrate”. Pop in and take a look, but don’t freak out. I’ll explain those at another time. Boot up your server and navigate to your homepage, if you’ve forgotten how to do this just run, “script/server” and visit “http://localhost:3000″. You will likely encounter a “Routing error”, that’s okay though! Later, we will discuss routes, which allow you to control the URL structure.

02_routing.jpg

Remember we created a scaffold for our model “Book”, well, the corresponding controller is located in “app/controllers/books_controller.rb”. Earlier I mentioned that the controller handles all the webrequests. By default, you can access a controller by it’s name, in this case, “books”. Change your browser’s URL to: “http://localhost:3000/books” and you should see this:

03_books-index.jpg

Well, what’s this…no books? Go ahead and add one! Before you get too excited, I want you to pay attention to the URL, notice that when you click “create” you are taken to “http://localhost:3000/books/new” this URL will correspond very closely with your application’s internal workings. .After you add a book, you should see a quick summary of the book you’ve inputted into the database; here’s one that I’ve added:

04_new-book.jpg05_book_created.jpg

Click the back button, and return to the index.

06_books-index.jpg

Wasn’t that simple? You have a basic bookstore where you can create, edit, update, and destroy books from a working database! Take some time to reread this tutorial and play with the application’s internal workings, get familiar with everything here because I will use it as a foundation from this point forward.

If you need the source code, you can download it here.

Was this helpful, do you have questions, or do you just want to bullshit? Leave me a comment! Feel like donating to my beer fund?

Check out part two, “Basic Rail’s routing and a journey into Views, and Controllers“!

Free online dating that’s truly free!

April 2nd was the cumulation of four months of work, yesterday we launched Meeta.com our free dating website. Using a rapid development framework, known to all of you guys as Ruby on Rails, we’ve been able to move from conceptual models to a production stable product in a very short amount of time!

Along the way, I’ve seen first had the power of Rails, the benefit of RESTful design, and the necessity of comcodehensive test coverage. Drop in, sign up, check it out! Now that we’ve hit our beta launch
date, I’ll be back with even more Rails tidbits that I’ve learned
during these four months :)

71-37-25-72:trunk jon$ rake stats
(in /Users/jon/Sites/meeta.com/trunk)
+----------------------+-------+-------+---------+---------+-----+-------+
| Name                 | Lines |   LOC | Classes | Methods | M/C | LOC/M |
+----------------------+-------+-------+---------+---------+-----+-------+
| Controllers          |  2071 |  1683 |      37 |     214 |   5 |     5 |
| Helpers              |   342 |   293 |       0 |      32 |   0 |     7 |
| Models               |  1766 |  1364 |      38 |     165 |   4 |     6 |
| Libraries            |   458 |   340 |       5 |      48 |   9 |     5 |
| Integration tests    |     0 |     0 |       0 |       0 |   0 |     0 |
| Functional tests     |  2106 |  1730 |      36 |     249 |   6 |     4 |
| Unit tests           |  1176 |   935 |      38 |     145 |   3 |     4 |
+----------------------+-------+-------+---------+---------+-----+-------+
| Total                |  7919 |  6345 |     154 |     853 |   5 |     5 |
+----------------------+-------+-------+---------+---------+-----+-------+
  Code LOC: 3680     Test LOC: 2665     Code to Test Ratio: 1:0.7