4

I have few question that bugs me off and need to be answered. Everything is related to the following tutorial Two Many-to-Many

Question 1

Does the join table using has_many need to have an id? or its best practice to remove the id? and add an index and using the two other primary key and set it unique and together?

Question 2

How can it be done in the migration of creating a table?

Question 3

After doing these relationship model and updating the data. I would like to create a new set of data everytime it is updated (to preserve the data). How would a controller would look in the update, new, create model?

Question 4

In the the middle table, I would like to set attributes such has a visible true, or false, how can I set also not just the third table but also the second table arguments

Community
  • 1
  • 1
Jseb
  • 1,926
  • 4
  • 29
  • 51

2 Answers2

3

First ... a word of caution: That railscast is very old. There may be syntactical things in that episode that have been dated by new versions of rails.

Question 1

If you are using the has_many through method then you have to have an id column in the join model because you are using a full blown model. As Ryan mentions in the episode, you'll choose this method if you need to track additional information. If you use the has_and_belongs_to_many method, you will not have an id column in your table.
If you want to achieve a check where you do not allow duplicates in your many-to-many association (ie allow the pairing of item a with item b and again allowing another record of item a to item b), you can use a simple validates line with a scope:

validates_uniqueness_of :model_a_id, :scope => [:model_b_id]


Question 2

You can add indices in your migrations with this code

add_index :table_name, [ :join_a_id, :join_b_id ], :unique => true, :name => 'by_a_and_b'

This would be inserted into the change block below your create_table statement (but not in that create_table block). Check out this question for some more details: In a join table, what's the best workaround for Rails' absence of a composite key?

Question 3

I'm not completely clear on what you're looking to accomplish but if you want to take some action every time a new record is inserted into the join model I would use the after_create active record hook. That would look something like this.

class YourJoinModel < ActiveRecord::Base

  after_create :do_something

  def do_something
    puts "hello world"
  end
end

That function, do_something, will be called each time a new record is created.

Question 4

Using the has_many through method will give you access to the additional attributes that you defined in that model on both sides of the relationship. For example, if you have this setup:

class Factory < ActiveRecord::Base
  has_many :widgets, :through => :showcases
end

class Widget < ActiveRecord::Base
  has_many :factories, :through => :showcases
end

class Showcases < ActiveRecord::Base
  belongs_to :factory
  belongs_to :widget

  attr_accessiable :factory_id, :widget_id, :visible
end

You could say something like

widget = Widget.first
shown = widget.showcases
shown.first.visible

or

shown = widget.showcases.where( :visible=> true )

You can also reach to the other association:

shown.first.factory
Community
  • 1
  • 1
barancw
  • 888
  • 9
  • 18
  • Thanks this clear me out i am assuming i would do widget = widget ... code in the controller in a create. Here my only last questions, if I have multiple model in one page is there a way for me to set up partial with an action? – Jseb Jul 30 '12 at 15:51
0

The reason for having an id column in an association is it gives you a way of deleting that specific association without concerning yourself with the relationship it has. Without that identifier, associations are hard to define outside of specifying all foreign keys.

For a trivial case where you have only two components to your key, this isn't that big a differentiator, but often you will have three or more as part of your unique constraint and there's where things get tricky.

Having an id also makes the relationship a first-class model. This can be useful when you're manipulating elements that have associated meta-data. It also means you can add meta-data effortlessly at a later date. This is what you mean by your "Question 4". Add those attributes to the join model.

Generally the join model is created like you would any other model. The primary key is the id and you create a series of secondary keys:

create_table :example_things |t|
  t.integer :example_id
  t.integer :thing_id
end

add_index :example_joins, [ :example_id, :thing_id ], :unique => true
add_index :example_joins, :thing_id

The main unique index serves to prevent duplication and allows lookups of key-pairs. The secondary serves as a way of extracting all example_id for a given thing_id.

The usual way to manipulate meta-data on the join model is to fetch those directly:

@example_things = @example.example_things.includes(:thing)

This loads both the ExampleThing and Thing models associated with an Example.

tadman
  • 208,517
  • 23
  • 234
  • 262
  • Thanks, this help me clear things out. What i mean by question 4 is how to manipulate the data, i have 3 table customer, music, and a musicmanager ( belongs to customerid, musicid) and I would like to add content to music but keeping track with music manager which has a value is visible true or false – Jseb Jul 30 '12 at 15:19