Model Relations


#1

Hi,

I am creating my databases and models and I need to use some
relationships. I am very new at this so any help or info at all would be
great. :slight_smile:

The concept is:
There are three resources: people, items and tags.

  • An item belongs to one person, the creator.
  • A person can create many items.
  • An item can have many tags.
  • A tag can be used on many items.

Here my models:


/* models/item.rb */
class Item < ActiveRecord::Base
belongs_to :person
has_many :tags
end


/* models/person.rb */
class Person < ActiveRecord::Base
has_many :items
end


/* models/tag.rb /
class Tag < ActiveRecord::Base
/
should I use ‘has_and_belongs_to_many’ here? */
end

Here’s the migrations:


/* db/migrate/1_create_items.rb /
class CreateItems < ActiveRecord::Migration
def self.up
create_table :items do |t|
t.string :name
t.belongs_to :person
/
what should I put here to create a relation to tags? */
end
end

def self.down
drop_table :items
end
end


/* db/migrate/2_create_people.rb /
class CreatePeople < ActiveRecord::Migration
def self.up
create_table :people do |t|
t.string :name
/
do I need something here to create a relation to items? */
end
end

def self.down
drop_table :people
end
end


/* db/migrate/3_create_tags.rb /
class CreateTags < ActiveRecord::Migration
def self.up
create_table :tags do |t|
t.string :name
/
what should I put here to create a relation to items? */
end
end

def self.down
drop_table :tags
end
end


#2

On Apr 10, 12:22 pm, Christoffer Brodd-reijer <rails-mailing-
removed_email_address@domain.invalid> wrote:

end
You could use has and belongs to many or has many through. Either way
you will need another table (the join table for the relationship
between tags and items), the existing tables are fine as is.
You might find http://guides.rubyonrails.org/association_basics.html
helpful.

Fred


#3

Frederick C. wrote:

On Apr 10, 12:22�pm, Christoffer Brodd-reijer <rails-mailing-
removed_email_address@domain.invalid> wrote:

end
You could use has and belongs to many or has many through. Either way
you will need another table (the join table for the relationship
between tags and items), the existing tables are fine as is.
You might find http://guides.rubyonrails.org/association_basics.html
helpful.

Fred

I went with using a joint table


/* db/migrate/3_create_tags.rb */

create_table :item_tags, :id => false do |t|
t.integer :tag
t.integer :item
end

Now I am coding the controller that creates the item. I am iterating
through each tag that the user typed in and I want this to happen:

  • Create a new tag in the ‘tags’ table if it does not already exists
  • Associate the tag and item by adding the pair to the ‘item_tags’ table

The idea here is that each tag should be only once in the tags table.
Here’s the controller function so far:


/* controllers/items_controller.rb */
def create
for tag in tags.split(’ ')
match = Tag.find(:first, :conditions => “name = ‘#{tag}’”)
unless match
Tag.create(:name => tag)
end

/* make association here */

end
end

Problem is, I don’t know how to add the association in the controller.
Also, am I doing the rest of the stuff right? Or maybe Rails can
automate this whole process somehow? Thanks,


#4

You can shorten this part up by using Tag.find_or_create_by_name, one
of the dynamic finder methods.
And I’d add a generic warning to NEVER use #{} interpolation directly
in anything you’re feeding to an AR conditions parameter, unless you
want to relearn the lesson of little Bobby Tables…

The final code will look something like:

def create
# find item, put in @item
@item.tags = params[:tags].split(’ ').map do |tag|
Tag.find_or_create_by_name(tag)
end
# do whatever else
end

Alternatively, you could encapsulate this behavior in the Item model,
using a virtual tags_attr or the like to do the parsing. I’d recommend
that you take a look at some of the approaches taken by
acts_as_taggable and it’s descendants.

–Matt J.

On Apr 10, 11:24 am, Christoffer Brodd-reijer <rails-mailing-