Ruby on Rails: ActiveRecord relationships almost make sense!

rails

Yesterday I was having a lot of issues getting ActiveRecord relationships to work.

The problem, as with my relationships with women, was all to do with my lack of understanding. 🙂

I posted up on the rails forum about my dilemma, and was lucky enough to get some fantastic help from one dude in particular , Duplex, who managed to walk me through all my errors and misunderstanding. Check it out here. I look like a retard!

So for my own benefit I am going to do a walkthrough here on ‘News from Above’ (how wanky does that sound?!) of what I did yesterday just to make sure I can.

This example with be an application that has a ‘job’ model (as in a job for a tv commercial) and a ‘director’ model (a tvc director).

———————————————

Create a rails project

in a shell/terminal change into a directory where you will have your RoR’s projects. Then enter:

rails yourprojectname

my app for this will be called ‘kapow’, and I want to use mysql as the database, not the default SQLite DB that comes with osx 10.5.

rails kapow -d mysql

next change directories into the new project

cd kapow

now we should create the database. There are probably many ways to do this but the following seems to be the most simple. using the ruby make command ‘rake’.

rake db:create

If all went well all that should come back in the shell/terminal is something like:

in /pathtoyourproject/kapow)

You can use apps like CocoaMySQL to view all ur MySQL databases/tables – but I have read DON’T edit the tables – do all that with Ruby/Rails.

now we need to build a ‘scaffold’ of the job model

The Job model that is created will have a ‘name’ attribute and a ‘director_id’ attribute.

ruby script/generate scaffold job name:string director_id:integer

I originally thought this is where I would want a ‘string’ field to store the director’s name in, but we are going to create another table for ‘director’. The ‘job’ table will simply store the ‘director_id’ number (actually the ‘id’ of the entry in the ‘director’ table).

Next we need to generate a scaffold for the ‘director’ model

ruby script/generate scaffold director name:string

Cool! Models are nearly ready. Now we need to open up the ruby files for the ‘director’ and ‘job’ models, and explain how they are associated – what their ‘relationship’ is.

A ‘migration’ file has been created in the ‘db’ folder. Now it just had to be run to populate the database with the models.

rake db:migrate

*From this point on it is all pretty much text editing. I use TextMate.

For this little app, the relationships in simple BOLD english are “A DIRECTOR HAS MANY JOBS” and “A JOB BELONGS TO A DIRECTOR”.

So in RoR’s terms for the director model – (“kapow/app/model/director.rb”):

class Director < ActiveRecord::Base
  has_many :jobs
end

and for the job model – (“kapow/app/model/job.rb”):
class Job < ActiveRecord::Base
belongs_to :director
end
Even cooler! So now the model’s know where they are with each other.
For this kapow app I want the user to be able to select from a list of directors when creating a new job – a ‘dropdown’ list. To get the director’s from the database we need to setup the ‘jobs_controller‘ to retrieve a list of director names from the database.
To do this we need to add a line of code to both the ‘new‘ action and ‘edit‘ action. (*** Just a note, from what I have read, an “action” is a “controller method”). The jobs_controller.rb file lives in (“kapow/app/controllers”).
@directors = Director.find(:all, :order => :name)
So each method will now look like:
  def edit
    @job = Job.find(params[:id])
    @directors = Director.find(:all, :order => :name)
  end
  
def new
  @job = Job.new
    @directors = Director.find(:all, :order => :name)
    respond_to do |format|
      format.html # new.html.erb
      format.xml  { render :xml => @job }
    end
  end
Now a few last things. The View! What we are going to see – what will be rendered to the screen. The html.erb files for ‘job’.
Firstly, the list of all jobs – the ‘index.html.erb’ and the ‘show.html.erb’.
The scaffold will have generated:
<h1>Listing jobs</h1>
<table>
<tr>
<th>Name</th>
<th>Director</th>
</tr>
<% for job in @jobs %>
<tr>
<td><%=h job.name %></td>
<td><%=h job.director_id %></td>
<td><%= link_to ‘Show’, job %></td>
<td><%= link_to ‘Edit’, edit_job_path(job) %></td>
<td><%= link_to ‘Destroy’, job, :confirm => ‘Are you sure?’, :method => :delete %></td>
</tr>
<% end %>
</table>
<br />
<%= link_to ‘New job’, new_job_path %>
We just need to update the line:
<td><%=h job.director_id %></td>
to read:
<td><%=h job.director.name %></td>
This will get the ‘name’ of the director from the ‘director’ table – otherwise it will just show the ‘id’ number of the director. The ‘*_id’ is some built in RoR built in thing I am yet to understand. I’ll update this post once I do! [THIS PART TOOK ME THE LONGEST TO UNDERSTAND!!!]
The last last thing to do is add the ‘dropdown’ menu. In the ‘edit.html.erb’ & ‘new.html.erb’ files, add this line:
<%= f.collection_select :director_id, @directors, :id, :name %>
above the line:
<%= f.text_field :director_id %>
so now the ‘edit.html.rb’ file should now look like (the ‘new.html.erb’ should look pretty similar:
<h1>Editing job</h1>
<%= error_messages_for :job %>
<% form_for(@job) do |f| %>
<p>
<b>Name</b><br />
<%= f.text_field :name %>
</p>
<p>
<b>Director</b><br />
<%= f.collection_select :director_id, @directors, :id, :name %>
<%= f.text_field :director_id %>
</p>
<p>
<%= f.submit “Update” %>
</p>
<% end %>
<%= link_to ‘Show’, @job %> |
<%= link_to ‘Back’, jobs_path %>
So now that is all setup we should be able to startup our webserver and start adding some jobs and directors.
Open up a new shell/terminal window, change directory to your ‘kapow’ project. To start the webserver, jump pack into the shell/terminal, and run this command (from within the ‘kapow’ directory:
ruby script/server
If all went well (which to can see in the shell/terminal), you should be able to go to your web browser and punchin:
localhost:3000/jobs