Topic: Working with migrations and associations

Dear RailsForum,

I've been tasked with putting together a new webapp from scratch: this seemed like a golden opportunity to pick up Rails, something I've been meaning to do for some time.

I'm quite comfortable with SQL, but I'd rather avoid it in this project --- it seems very un-Rails to write it raw.

Briefly, a target has a type, and a target may belong to any number of groups. target belongs_to type, type has_many targets, target belongs_to_many groups through membership, group has_many targets through membership. Right?

I'm at a loss as far as figuring out two things. One, how to put the above into pure migrations. Two, the proper Rails method to handle displaying the above. Ideally, I want users to add a target, have the option to associate with a type or create a new type, and then finally be able to add the target to any number of existing groups or create a new group.

The tutorials I've seen rely on, for lack of a better term, smoke and mirrors --- applications that are simple enough (single table, usually) to be handled by a default-arguments scaffold. Whenever I see association examples, I see copious amounts of SQL...which just feels wrong.

Am I simply looking in the wrong place?

Re: Working with migrations and associations

The schema sounds fairly standard. You can do it in migrations like this:

create_table :types do |t|

create_table :targets do |t|
  type_id :integer

create_table :memberships do |t|

create_table :groups do |t|

Here's how you could set up the associations:

class Type < ActiveRecord::Base
  has_many :targets

class Target < ActiveRecord::Base
  belongs_to :type
  has_many :memberships
  has_many :groups, :through => :memberships

class Membership < ActiveRecord::Base
  belongs_to :target
  belongs_to :group

class Group < ActiveRecord::Base
  has_many :memberships
  has_many :targets, :through => :memberships

As for fetching records, you shouldn't need to use raw SQL unless the query needs to be complicated. Most of the time you will just do simple stuff like this:

# controller
@group = Group.find(params[:id])

# view
<% for target in @group.targets %>
  Type: <%= %>
<% end %>

As for everything else, it really depends upon how you want the interface to look and behave. There are many ways to handle relationships which is one reason Rails doesn't automatically create the interface for you.

One thing you might do is make a Type select box on the target form:

<%= collection_select :target, :type, Type.find(:all), :id, :name %>

Or something like that.

It is common to create a controller for each model to handle basic CRUD operations for that model. This controller usually takes the plural form of the model name.

"type" is a reserved word, so you should probably rename it to avoid any problems.

Railscasts - Free Ruby on Rails Screencasts