ruby
Ruby on Rails Project - To Do List #4
Feb 18 2008 05:19 PM Filed in: Ruby
Well, I sure do let a lot of time go by between these
posts. For a simple Rails project that will take
around an hour or so to code, it's taken over a month
to write the posts about it.
When I last left off we had a browser interface that would display a list of Projects, and if you clicked on one of those Projects you would be presented with a page displaying a list of Tasks associated with that Project. This is a great start to a Project Tracking application, but it's missing a big piece...an interface for allowing the user to enter the Projects and Tasks through the web browser. Everything we've added so far has happened from the command line. So, that is what I'll cover this time, adding a user interface for entering this information.
The page used for displaying the Projects is located at /app/views/projects/index.rhtml. The code is pretty simple
We'll add the ability to add new Project to this same page, it will be at the top of the page. The existing projects will be listed below it.
First thing we'll do is update index.rhtml with the following code
This provides us with a text box and a button wrapped in a form that will submit to the 'new' method in the Project controller. The form should look like this if you view it in the browser at http://localhost:3000/projects/
Now we need to add the 'new' method to the Project Controller. This is located in /app/controller/projects_controller.rb. Add the following code
This code is pretty simple. When the user submits a new Project name, it comes over in the params object as a hash, with ':project' as the hash name, and ':name' as a key with the value the key corresponds to as the value they entered. Then we call the Save method and redirect back to index, which will redisplay the page with the new Project showing in the list.
This works great, you can add new Projects all day long, but there is an issue. We should have some sort of validation. We should validate that the user actually enters a value before clicking the button to create a project. We should also make sure the Project name they enter is unique. In most instances this would require a lot of coding on the developers part, but not in Rails. This is all taken care of. There are some pre-built validations, we'll use the validates_presence_of and validates_uniqueness_of validations, to check that the value has a length greater than 0 and also that the value is not already present in the database. We just need to add the validation calls to the Project model. The model is located at /app/models/project.rb, update it to look like this
Now if you try to add a blank Project or one with a name already taken, nothing happens. Once we actually work on a layout to make this site presentable we can display error messages, but for the time being not having it save bad data is good enough.
Now we have to repeat the steps above to all the user the ability to add new Tasks to the project. Update the form that displays the tasks, which is located in /app/views/projects/details.rhtml. Add the following code after the <h1> tags
This gives us a form that looks like this
Next we add the 'addtask' method to the Project Controller, which will create a new instance of a Task with the information entered by the user, find the Project that the task is going to be associated with, and adds the task to the tasks array of the Project, then it saves the project.
Add the following to the Task model, and you are done.
We'll allow duplicate task names, but the task does need a name entered.
That's all for this time. Next time we will allow updating and deleting of tasks. Also, we'll need to show overdue tasks.
When I last left off we had a browser interface that would display a list of Projects, and if you clicked on one of those Projects you would be presented with a page displaying a list of Tasks associated with that Project. This is a great start to a Project Tracking application, but it's missing a big piece...an interface for allowing the user to enter the Projects and Tasks through the web browser. Everything we've added so far has happened from the command line. So, that is what I'll cover this time, adding a user interface for entering this information.
The page used for displaying the Projects is located at /app/views/projects/index.rhtml. The code is pretty simple
<h1>Projects</h1>
<ul>
<% @projects.each do
|project| %>
<li><%=
link_to project.name, :action => 'details', :id
=> project.id %></li>
<% end %>
</ul>
We'll add the ability to add new Project to this same page, it will be at the top of the page. The existing projects will be listed below it.
First thing we'll do is update index.rhtml with the following code
<!-- Form for adding a new Project -->
<% form_tag :action => :new do %>
Project Name: <%=
text_field :project, :name %>
<%= submit_tag 'Add new
project' %>
<% end %>
This provides us with a text box and a button wrapped in a form that will submit to the 'new' method in the Project controller. The form should look like this if you view it in the browser at http://localhost:3000/projects/
Now we need to add the 'new' method to the Project Controller. This is located in /app/controller/projects_controller.rb. Add the following code
def new
@newproject = params[:project]
Project.new(@newproject).save
redirect_to :action => :index
end
This code is pretty simple. When the user submits a new Project name, it comes over in the params object as a hash, with ':project' as the hash name, and ':name' as a key with the value the key corresponds to as the value they entered. Then we call the Save method and redirect back to index, which will redisplay the page with the new Project showing in the list.
This works great, you can add new Projects all day long, but there is an issue. We should have some sort of validation. We should validate that the user actually enters a value before clicking the button to create a project. We should also make sure the Project name they enter is unique. In most instances this would require a lot of coding on the developers part, but not in Rails. This is all taken care of. There are some pre-built validations, we'll use the validates_presence_of and validates_uniqueness_of validations, to check that the value has a length greater than 0 and also that the value is not already present in the database. We just need to add the validation calls to the Project model. The model is located at /app/models/project.rb, update it to look like this
class Project < ActiveRecord::Base
has_many :tasks
validates_presence_of :name
validates_uniqueness_of :name
end
Now if you try to add a blank Project or one with a name already taken, nothing happens. Once we actually work on a layout to make this site presentable we can display error messages, but for the time being not having it save bad data is good enough.
Now we have to repeat the steps above to all the user the ability to add new Tasks to the project. Update the form that displays the tasks, which is located in /app/views/projects/details.rhtml. Add the following code after the <h1> tags
<% form_tag :action => :addtask, :id =>
@project.id do %>
Task Name: <%= text_field
:task, :name %><br />
Due Date: <%=
date_select('range', 'due_date', : order =>
[:month, :day, :year]) %><br />
<%= submit_tag 'Add new
task' %>
<% end %>
This gives us a form that looks like this
Next we add the 'addtask' method to the Project Controller, which will create a new instance of a Task with the information entered by the user, find the Project that the task is going to be associated with, and adds the task to the tasks array of the Project, then it saves the project.
def addtask
#create task
@task = Task.new(params[:task])
@task.is_complete = false
#add to project
@project =
Project.find_by_id(params[:id])
@project.tasks << @task
@project.save
redirect_to :action => 'details', :id
=> params[:id]
end
Add the following to the Task model, and you are done.
validates_presence_of :name
We'll allow duplicate task names, but the task does need a name entered.
That's all for this time. Next time we will allow updating and deleting of tasks. Also, we'll need to show overdue tasks.
|
Ruby on Rails Project - To Do List #3
Jan 17 2008 10:53 PM Filed in: Ruby
In step
two of my PC Task project I created my
models for Projects and Tasks. In step three I
will move on to the Controllers and Views.
We'll start off with the Projects Controller. Just like we used a script to generate our Model, we can do the same thing with our Controller. The syntax for creating a Controller is
$ ruby script/generate controller controller_name
So, to create our Projects Controller type the following
$ ruby script/generate controller Projects index
You should receive something similar to the following
exists app/controllers/
exists app/helpers/
create app/views/projects
exists test/functional/
create app/controllers/projects_controller.rb
create test/functional/projects_controller_test.rb
create app/helpers/projects_helpers.rb
create app/views/projects/index.rhtml
So, you'll probably notice I added an extra argument on to the end of that command, 'index'. The default name for the file that is accessed when a user visits your site is the index page, so adding this extra argument just created the index.rhtml page for us. If you leave it off, you can always create it later yourself.
Before I move on, I never did define what Model, View, Controller really meant. Here's a couple quick definitions.
Model - handles data and business logic
Controller - handles user interface and application logic
View - handles GUI objects and presentation logic
In a web application the chain of events is
a. Web browser sends a request for a page to the controller.
b. Controller gets the data it needs from the model.
c. Controller renders the page then sends it to the view.
d. View displays the page in the browser.
OK, if you were to start the application, using the following command
$ ruby script/server
and you open a browser and navigate to http://localhost:3000/projects, you should see a page that has the following displayed
Now, we need to decide what we want to display in the View, so we can code for this in the Controller. I think at the moment we can just display a list of all the Projects.
Now, before I go any further I want to do a quick introduction to a feature of Rails called Scaffolding. Scaffolding is a tool that can quickly create a view for you that you can use to interact with your model. The view that's created lists all the data in the table and creates an interface for performing your CRUD operations. Scaffolding used to be the selling point of Rails, back when it was the new kid on the block. It's a fun little feature, but I think most developers forgo it for creating their own Controller and View. Scaffolding is very easy. Open the projects controller ($ mate app/controller/projects_controller.rb) and modify the file to look like the following
class ProjectsController < ApplicationController
scaffold :project
end
Now, save the file and refresh the page in your browser that points to http://localhost:3000/projects. Your web page should now look like this
I had created a Test Project in step #2, so it is showing here. As you can see, it has all of the CRUD operations on the screen. This is a cool feature, something I would love sometimes at work in .NET WinForms (I think something similar to this is available in ASP.NET 2008, which is a pretty good clone of Rails, way to innovate again Microsoft), but it's not the route we will take. Instead we will go "our own route".
Modify the Controller file to look like the following
class ProjectsController < ApplicationController
def index
@projects = Project.find(:all)
end
end
Here we define an index action and the find(:all) returns all records in the Projects table. If you refresh the page in your browser you are back to this page
We haven't defined any code in our view (index.rhtml), so nothing is displayed yet. We now need to update the View to show a list of Projects. Open the index.rhtml file and update it like so
<h1>Projects</h1>
<ul>
<% @projects.each do |project| %>
<li><%= link_to project.name, :action => 'details', :id => project.id %></li>
<% end %>
</ul>
What all is this doing? @project is an instance variable, he was defined in the Controller. The line with @projects.each do |project| is basically looping through the items stored in @projects, which is the result of the find(:all) command, and storing the current item in project, which is then used when writing out the list. The link_to command is an HTML helper that wraps the item in anchor tags. If you view the page in the browser now you should see the following
Not as cool and exciting as what was created by Scaffolding, but it's a start. If you click on the link you will receive an error. This is because we defined an action called 'details' that we haven't defined yet. Let's do that now. Add the following to the Projects Controller.
def details
@project = Project.find_by_id(params[:id])
@tasks = @project.tasks
end
This uses the project.id that is passed as id in the parameters and gets the tasks related to that project. Now we need to create a details.rhtml page. Create one in the same directory as index.rhtml and add the following code
<h1><%= @project.name %></h1>
<ol>
<% @tasks.each do |task| %>
<li><%= task.name %> <%= task.due_date %> <%= task.is_complete %></li>
<% end %>
</ol>
Now, if you click on the link on index.html you should see a page similar to the following
Not the prettiest page in the world, but it will do for now.
We now have a Controller that will gather the information about the Projects and the associated Tasks, and will display that information in our index and details View.
In step 4 I will add more of the CRUD functionality.
We'll start off with the Projects Controller. Just like we used a script to generate our Model, we can do the same thing with our Controller. The syntax for creating a Controller is
$ ruby script/generate controller controller_name
So, to create our Projects Controller type the following
$ ruby script/generate controller Projects index
You should receive something similar to the following
exists app/controllers/
exists app/helpers/
create app/views/projects
exists test/functional/
create app/controllers/projects_controller.rb
create test/functional/projects_controller_test.rb
create app/helpers/projects_helpers.rb
create app/views/projects/index.rhtml
So, you'll probably notice I added an extra argument on to the end of that command, 'index'. The default name for the file that is accessed when a user visits your site is the index page, so adding this extra argument just created the index.rhtml page for us. If you leave it off, you can always create it later yourself.
Before I move on, I never did define what Model, View, Controller really meant. Here's a couple quick definitions.
Model - handles data and business logic
Controller - handles user interface and application logic
View - handles GUI objects and presentation logic
In a web application the chain of events is
a. Web browser sends a request for a page to the controller.
b. Controller gets the data it needs from the model.
c. Controller renders the page then sends it to the view.
d. View displays the page in the browser.
OK, if you were to start the application, using the following command
$ ruby script/server
and you open a browser and navigate to http://localhost:3000/projects, you should see a page that has the following displayed
Now, we need to decide what we want to display in the View, so we can code for this in the Controller. I think at the moment we can just display a list of all the Projects.
Now, before I go any further I want to do a quick introduction to a feature of Rails called Scaffolding. Scaffolding is a tool that can quickly create a view for you that you can use to interact with your model. The view that's created lists all the data in the table and creates an interface for performing your CRUD operations. Scaffolding used to be the selling point of Rails, back when it was the new kid on the block. It's a fun little feature, but I think most developers forgo it for creating their own Controller and View. Scaffolding is very easy. Open the projects controller ($ mate app/controller/projects_controller.rb) and modify the file to look like the following
class ProjectsController < ApplicationController
scaffold :project
end
Now, save the file and refresh the page in your browser that points to http://localhost:3000/projects. Your web page should now look like this
I had created a Test Project in step #2, so it is showing here. As you can see, it has all of the CRUD operations on the screen. This is a cool feature, something I would love sometimes at work in .NET WinForms (I think something similar to this is available in ASP.NET 2008, which is a pretty good clone of Rails, way to innovate again Microsoft), but it's not the route we will take. Instead we will go "our own route".
Modify the Controller file to look like the following
class ProjectsController < ApplicationController
def index
@projects = Project.find(:all)
end
end
Here we define an index action and the find(:all) returns all records in the Projects table. If you refresh the page in your browser you are back to this page
We haven't defined any code in our view (index.rhtml), so nothing is displayed yet. We now need to update the View to show a list of Projects. Open the index.rhtml file and update it like so
<h1>Projects</h1>
<ul>
<% @projects.each do |project| %>
<li><%= link_to project.name, :action => 'details', :id => project.id %></li>
<% end %>
</ul>
What all is this doing? @project is an instance variable, he was defined in the Controller. The line with @projects.each do |project| is basically looping through the items stored in @projects, which is the result of the find(:all) command, and storing the current item in project, which is then used when writing out the list. The link_to command is an HTML helper that wraps the item in anchor tags. If you view the page in the browser now you should see the following
Not as cool and exciting as what was created by Scaffolding, but it's a start. If you click on the link you will receive an error. This is because we defined an action called 'details' that we haven't defined yet. Let's do that now. Add the following to the Projects Controller.
def details
@project = Project.find_by_id(params[:id])
@tasks = @project.tasks
end
This uses the project.id that is passed as id in the parameters and gets the tasks related to that project. Now we need to create a details.rhtml page. Create one in the same directory as index.rhtml and add the following code
<h1><%= @project.name %></h1>
<ol>
<% @tasks.each do |task| %>
<li><%= task.name %> <%= task.due_date %> <%= task.is_complete %></li>
<% end %>
</ol>
Now, if you click on the link on index.html you should see a page similar to the following
Not the prettiest page in the world, but it will do for now.
We now have a Controller that will gather the information about the Projects and the associated Tasks, and will display that information in our index and details View.
In step 4 I will add more of the CRUD functionality.
Ruby on Rails Project - To Do List # 2
Jan 13 2008 09:14 PM Filed in: Ruby
It's been a month since I made the first post for
this personal project. What can I say, it was the
holidays, and I had other stuff on my mind. I'm still
interested in learning Ruby and Rails, so I'm not
abandoning the project. Here's part two.
My To-Do List web application is going to start off pretty simple. The first thing I need to do is consider the entities that are needed. To begin I will just have a Project entity and a Task entity. A Project can contain one or more Tasks. A Project will have one attribute, a Name. A Task will have a couple attributes: Name, Due Date, Project ID and an Is Complete flag.
Just like Rails provided us with scripts to generate our directory structure, it also provides us with a script to generate our Model. Remember, Rails is based on the MVC (Model, View, Controller) Design Pattern. The Model creation syntax is
$ ruby script/generate model model_name
Now we create our two Models
$ ruby script/generate model Project
$ ruby script/generate model Task
Here's an example of the output you should receive
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/project.rb
create test/unit/project_test.rb
create test/fixtures/projects.yml
create db/migrate
create db/migrate/001_create_projects.rb
As you can see, it not only generates our Model, but also the Test files for running our Unit Tests and files for migrating our database changes. This is one thing I enjoy about Rails, you don't have to use a tool to create your database tables and the columns in those tables, you can use the files that are generated. I recommend doing this, since Rails will automatically create Unique ID fields for you.
So, now that we have the Model created, we will add the code to the migrate file to create the columns we need.
If you look at the file 001_create_projects.rb in TextMate, you should see the following
class CreateProjects < ActiveRecord::Migration
def self.up
create_table :projects do |t|
end
end
def self.down
drop_table :projects
end
end
If we performed a migration with this, it would create a projects table for us, and it would have a Unique ID field, but nothing else. We can modify it to add the fields we need, which is just a Name.
class CreateProjects < ActiveRecord::Migration
def self.up
create_table :projects do |t|
t.column :name, :string
end
end
def self.down
drop_table :projects
end
end
The code for 002_create_tasks.rb is
class CreateTasks < ActiveRecord::Migration
def self.up
create_table :tasks do |t|
t.column :name, :string
t.column :due_date, :datetime
t.column :project_id, :integer, :null => false
t.column :is_complete, :boolean
end
end
def self.down
drop_table :tasks
end
end
We can now use Rake to apply these changes to the database. You should receive output similar to this
$ rake db:migrate
(in /Users/punkcoder/Development/Ruby/pctask)
== CreateProjects: migrating ==================================
-- create_table(:projects)
-> 0.0257s
== CreateProjects: migrated (0.0259s) ===========================
== CreateTasks: migrating ==================================
-- create_table(:tasks)
-> 0.0034s
== CreateTasks: migrated (0.0036s) ===========================
If you go look at the database you should see the tables with the columns. Now we can define the relationships between the tables. Ours is actually pretty simple: a Project has_many Tasks. So, how do we define the relationship? We do it in the Model. Go to app/models/project.rb, it should look like this
class Project < ActiveRecord::Base
end
(Oh yeah, really quick, you notice the < in the syntax above, well, Ruby is an Object Oriented language, and this syntax means Project inherits from ActiveRecord.)
So, to say that Project has many Tasks you pretty much state it
class Project < ActiveRecord::Base
has_many :tasks
end
This is a two way relationship, so we also edit app/models/task.rb to say that a Task belongs to a Project
class Task < ActiveRecord::Base
belongs_to :project
end
Cool, now that we have that set up we can actually test this. Rails has an interactive development environment in the console which we can use. Type the following
script/console
You should see
Loading development environment.
>>
So, the first thing we will do is create a new Project. Rails has created the method we need to do this, it's the 'new' method. To create a new Project type the following
>> project = Project.new(:name => 'Test Project')
You should get the response
=> #<Project:0x24b614c @new_record=true, @attributes={"name"=>"Test Project"}>
We have created a Project named "Test Project". If you go look in the database you won't see anything, because we haven't called Save, instead it's just in memory at the moment. It has been created though, so you can inspect it
>> project.name
=> "Test Project"
>> project.new_record?
=> true
>> project.id
=> nil
Since it hasn't been saved in the database a Unique ID hasn't been assigned. Now, here's the cool part. Remember how we defined that a Project has many Tasks in our Model? Well, if you type the following, you get a nice surprise
>> project.tasks
=> [ ]
That's right, we never added a tasks field to the database, but we set up a relationship, and here it shows an empty array waiting for some tasks.
Now we can save it. Again, just like the 'new' there's also a 'save' method we can call.
>> project.save
=> true
>> project.id
=> 1
Now we have a Unique ID.
Now we can create a task, much like we created a project
>> task = Task.new(:name => 'Test Task 1', :due_date => Time.now, :is_complete => false)
We can't save the task yet, if you call Save you get an error
>> task.save
ActiveRecord::StatementInvalid: MySql::Error: #23000Column 'project_id' cannot be null.
We set the constraint on the project_id field that said it couldn't be null. To save the Task it needs to belong to the Project we created. We can add it using the << operand
>> project.tasks << task
Now you can call task.save and project.save
If you call project.tasks it will list all the tasks. You can access the attributes on the task like this
>> project.tasks[0].name
=> "Test Task 1"
Rails creates methods to allow you to find items in the database for creating an instance of an object. An example of this is
>> test_project = Project.find_by_name('Test Project')
now you can perform the same inspection as before
>> test_project.tasks[0].due_date
==> Sun Jan 13 22:34:17 -0500 2008
Rails actually creates a find for every column, so you can do something like the following
>> test_task = Task.find_by_project_id(1)
>> test_task.name
=> "Test Task 1"
Well, that's enough for now. I'll try not to take another month before writing up Part 3.
My To-Do List web application is going to start off pretty simple. The first thing I need to do is consider the entities that are needed. To begin I will just have a Project entity and a Task entity. A Project can contain one or more Tasks. A Project will have one attribute, a Name. A Task will have a couple attributes: Name, Due Date, Project ID and an Is Complete flag.
Just like Rails provided us with scripts to generate our directory structure, it also provides us with a script to generate our Model. Remember, Rails is based on the MVC (Model, View, Controller) Design Pattern. The Model creation syntax is
$ ruby script/generate model model_name
Now we create our two Models
$ ruby script/generate model Project
$ ruby script/generate model Task
Here's an example of the output you should receive
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/project.rb
create test/unit/project_test.rb
create test/fixtures/projects.yml
create db/migrate
create db/migrate/001_create_projects.rb
As you can see, it not only generates our Model, but also the Test files for running our Unit Tests and files for migrating our database changes. This is one thing I enjoy about Rails, you don't have to use a tool to create your database tables and the columns in those tables, you can use the files that are generated. I recommend doing this, since Rails will automatically create Unique ID fields for you.
So, now that we have the Model created, we will add the code to the migrate file to create the columns we need.
If you look at the file 001_create_projects.rb in TextMate, you should see the following
class CreateProjects < ActiveRecord::Migration
def self.up
create_table :projects do |t|
end
end
def self.down
drop_table :projects
end
end
If we performed a migration with this, it would create a projects table for us, and it would have a Unique ID field, but nothing else. We can modify it to add the fields we need, which is just a Name.
class CreateProjects < ActiveRecord::Migration
def self.up
create_table :projects do |t|
t.column :name, :string
end
end
def self.down
drop_table :projects
end
end
The code for 002_create_tasks.rb is
class CreateTasks < ActiveRecord::Migration
def self.up
create_table :tasks do |t|
t.column :name, :string
t.column :due_date, :datetime
t.column :project_id, :integer, :null => false
t.column :is_complete, :boolean
end
end
def self.down
drop_table :tasks
end
end
We can now use Rake to apply these changes to the database. You should receive output similar to this
$ rake db:migrate
(in /Users/punkcoder/Development/Ruby/pctask)
== CreateProjects: migrating ==================================
-- create_table(:projects)
-> 0.0257s
== CreateProjects: migrated (0.0259s) ===========================
== CreateTasks: migrating ==================================
-- create_table(:tasks)
-> 0.0034s
== CreateTasks: migrated (0.0036s) ===========================
If you go look at the database you should see the tables with the columns. Now we can define the relationships between the tables. Ours is actually pretty simple: a Project has_many Tasks. So, how do we define the relationship? We do it in the Model. Go to app/models/project.rb, it should look like this
class Project < ActiveRecord::Base
end
(Oh yeah, really quick, you notice the < in the syntax above, well, Ruby is an Object Oriented language, and this syntax means Project inherits from ActiveRecord.)
So, to say that Project has many Tasks you pretty much state it
class Project < ActiveRecord::Base
has_many :tasks
end
This is a two way relationship, so we also edit app/models/task.rb to say that a Task belongs to a Project
class Task < ActiveRecord::Base
belongs_to :project
end
Cool, now that we have that set up we can actually test this. Rails has an interactive development environment in the console which we can use. Type the following
script/console
You should see
Loading development environment.
>>
So, the first thing we will do is create a new Project. Rails has created the method we need to do this, it's the 'new' method. To create a new Project type the following
>> project = Project.new(:name => 'Test Project')
You should get the response
=> #<Project:0x24b614c @new_record=true, @attributes={"name"=>"Test Project"}>
We have created a Project named "Test Project". If you go look in the database you won't see anything, because we haven't called Save, instead it's just in memory at the moment. It has been created though, so you can inspect it
>> project.name
=> "Test Project"
>> project.new_record?
=> true
>> project.id
=> nil
Since it hasn't been saved in the database a Unique ID hasn't been assigned. Now, here's the cool part. Remember how we defined that a Project has many Tasks in our Model? Well, if you type the following, you get a nice surprise
>> project.tasks
=> [ ]
That's right, we never added a tasks field to the database, but we set up a relationship, and here it shows an empty array waiting for some tasks.
Now we can save it. Again, just like the 'new' there's also a 'save' method we can call.
>> project.save
=> true
>> project.id
=> 1
Now we have a Unique ID.
Now we can create a task, much like we created a project
>> task = Task.new(:name => 'Test Task 1', :due_date => Time.now, :is_complete => false)
We can't save the task yet, if you call Save you get an error
>> task.save
ActiveRecord::StatementInvalid: MySql::Error: #23000Column 'project_id' cannot be null.
We set the constraint on the project_id field that said it couldn't be null. To save the Task it needs to belong to the Project we created. We can add it using the << operand
>> project.tasks << task
Now you can call task.save and project.save
If you call project.tasks it will list all the tasks. You can access the attributes on the task like this
>> project.tasks[0].name
=> "Test Task 1"
Rails creates methods to allow you to find items in the database for creating an instance of an object. An example of this is
>> test_project = Project.find_by_name('Test Project')
now you can perform the same inspection as before
>> test_project.tasks[0].due_date
==> Sun Jan 13 22:34:17 -0500 2008
Rails actually creates a find for every column, so you can do something like the following
>> test_task = Task.find_by_project_id(1)
>> test_task.name
=> "Test Task 1"
Well, that's enough for now. I'll try not to take another month before writing up Part 3.
Ruby on Rails Project - To Do List # 1 (Reprint)
Jan 13 2008 08:36 PM Filed in: Ruby
When I lost the files on my backup drive I lost my
original blog files, which also meant the history of
posts on my site. This is a reprint of part 1 of my
Ruby To Do List project, since I am about to post
part 2.
Originally posted on Dec 11, 2007...Good thing I'm not this slow at doing development at work
>>
I am finally getting around to starting the personal Ruby on Rails project I wanted to work on, as a way to learn Rails development better. You can only learn so much from a book, real world experience helps a lot.
My plan is to build a simple To Do List application, I'll call it "PC-Task", just to add my Punk Coder touch. I am going to document each step of the process.
The first step is going to be pretty simple, it's just getting everything set up, creating the directory structure and getting the database created.
I am using the install of Ruby and Rails that came pre-installed on Leopard, Mac OS X.
These are: ruby 1.8.6 and rails 1.2.3
I am also using MySQL for my database.
Ruby on Rails has a directory structure which will be created with the following command
$ rails project_name
So, the first thing I will do is create this directory structure
$ rails pctask --database=mysql
Adding the --database=mysql switch will configure the application to use MySQL, saving you a step in editing the file.
I'm not going to list all of the files that get created, but here's what the directory structure looks like
$ cd pctask
$ ls -p
README
app/
config/
doc/
log/
script/
tmp/
Rakefile
components/
db/
lib/
public/
test/
vendor/
The bulk of where we work is in the application directory (app/), which contains the controllers, helpers, models and view directories.
Another important directory is the script/ directory. You will use this a lot in your development. One important thing in there is the server which our application will run on. We will use Mongrel, which listens on port 3000. You start Mongrel with the following command.
$ script/server
Once it's started you can open a browser window and go to http://localhost:3000/. This will bring up a default Welcome to Rails page with some Rails info.
The next thing to do will be to set up the database. I know the geeky thing is to do all your MySQL administration from the command line, but I am going to use a graphical environment called 'CocoaMySQL', a free tool you can find on the web.
I create a couple new databases named 'pctask_development', 'pctask_test' and 'pctask_production', at localhost using the root user. Now that the databases are created, we need to configure the application to connect to it. This is done in the database.yml file located in the config directory. If you open this in TextMate (my editor of choice), you should see a section that looks like this:
$ mate config/database.yml
development:
adapter: mysql
database: pctask_development
username: root
password:
host: localhost
This style of markup is YAML (YAML Ain't Markup Language), which is why it has the .yml extension. It's easy to read and something you use often in Rails development.
Since we used the --database=mysql switch at the beginning the adapter parameter is already filled out for us. Actually, we shouldn't have to make any changes, unless you've changed the default blank password for root user on localhost. If so, fill it out.
Now we can test the database connection. To do this, we will perform a database migration using the rake command. Type the following:
$ rake db:migrate
You should get output similar to the following if all worked well:
(in /Users/punkcoder/Development/Ruby/pctask)
If you receive an error, check to make sure your database is running. You can do this from the command line with the following command:
$ ps -ax | grep mysql
You should receive a couple lines of output showing you the mysql processes that are running. If nothing is running start MySQL
$ sudo /usr/local/mysql/bin/safe_mysqld
If MySQL is running and you receive an error, check the info in database.yml again.
That's all for now. We have the foundation set up to start development.
Originally posted on Dec 11, 2007...Good thing I'm not this slow at doing development at work
>>
I am finally getting around to starting the personal Ruby on Rails project I wanted to work on, as a way to learn Rails development better. You can only learn so much from a book, real world experience helps a lot.
My plan is to build a simple To Do List application, I'll call it "PC-Task", just to add my Punk Coder touch. I am going to document each step of the process.
The first step is going to be pretty simple, it's just getting everything set up, creating the directory structure and getting the database created.
I am using the install of Ruby and Rails that came pre-installed on Leopard, Mac OS X.
These are: ruby 1.8.6 and rails 1.2.3
I am also using MySQL for my database.
Ruby on Rails has a directory structure which will be created with the following command
$ rails project_name
So, the first thing I will do is create this directory structure
$ rails pctask --database=mysql
Adding the --database=mysql switch will configure the application to use MySQL, saving you a step in editing the file.
I'm not going to list all of the files that get created, but here's what the directory structure looks like
$ cd pctask
$ ls -p
README
app/
config/
doc/
log/
script/
tmp/
Rakefile
components/
db/
lib/
public/
test/
vendor/
The bulk of where we work is in the application directory (app/), which contains the controllers, helpers, models and view directories.
Another important directory is the script/ directory. You will use this a lot in your development. One important thing in there is the server which our application will run on. We will use Mongrel, which listens on port 3000. You start Mongrel with the following command.
$ script/server
Once it's started you can open a browser window and go to http://localhost:3000/. This will bring up a default Welcome to Rails page with some Rails info.
The next thing to do will be to set up the database. I know the geeky thing is to do all your MySQL administration from the command line, but I am going to use a graphical environment called 'CocoaMySQL', a free tool you can find on the web.
I create a couple new databases named 'pctask_development', 'pctask_test' and 'pctask_production', at localhost using the root user. Now that the databases are created, we need to configure the application to connect to it. This is done in the database.yml file located in the config directory. If you open this in TextMate (my editor of choice), you should see a section that looks like this:
$ mate config/database.yml
development:
adapter: mysql
database: pctask_development
username: root
password:
host: localhost
This style of markup is YAML (YAML Ain't Markup Language), which is why it has the .yml extension. It's easy to read and something you use often in Rails development.
Since we used the --database=mysql switch at the beginning the adapter parameter is already filled out for us. Actually, we shouldn't have to make any changes, unless you've changed the default blank password for root user on localhost. If so, fill it out.
Now we can test the database connection. To do this, we will perform a database migration using the rake command. Type the following:
$ rake db:migrate
You should get output similar to the following if all worked well:
(in /Users/punkcoder/Development/Ruby/pctask)
If you receive an error, check to make sure your database is running. You can do this from the command line with the following command:
$ ps -ax | grep mysql
You should receive a couple lines of output showing you the mysql processes that are running. If nothing is running start MySQL
$ sudo /usr/local/mysql/bin/safe_mysqld
If MySQL is running and you receive an error, check the info in database.yml again.
That's all for now. We have the foundation set up to start development.