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 present 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 => Booting Mongrel (use 'script/server webrick' to force WEBrick) => Rails application starting on http://0.0.0.0:3000 => Call with -d to detach => 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 => stop. USR2 => restart. INT => stop (no restart). ** Rails signals registered. HUP => 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:
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) -> 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.
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:
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:
Click the back button, and return to the index.
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“!