I want to share the primary key among several tables, and then to also
use it as the foreign key for has_one associations.
I have models "Person", "Instructor", and "Member" (tables "people",
"instructors", and "members").
Instructors and members of an association are people, so i plan to store
their personal information in "people" table, and to store a foreign key
"person_id" in "instructors" and "members" tables.
I also plan to have the associations:
class Person < ActiveRecord::Base
has_one :instructor, :dependent => :destroy
has_one :member, :dependent => :destroy
end
class Instructor < ActiveRecord::Base
belongs_to :person
end
class Member < ActiveRecord::Base
belongs_to :person
end
It is possible for a same person to be an instructor and a member in the
same time, or neither of two.
Now i do not need "id" in "instructors" and "members" tables, as i can
use "person_id" as the primary key.
I plan to create the tables with migrations like these:
class CreateInstructors < ActiveRecord::Migration
def self.up
create_table :instructors, :primary_key => "person_id" do |t|
t.text :presentation
t.binary :photo
...
end
end
...
end
...
class CreateMembers < ActiveRecord::Migration
def self.up
create_table :members, :primary_key => "person_id" do |t|
t.date :member_since
...
end
end
...
end
My question is: is this going to work, or will i encounter some
unresolvable issues?
(For example, when creating a new Instructor, how to specify its primary
key "person_id" to be equal to the "id" of an existing person?)
Thanks.
Alexey.
--
Posted via http://www.ruby-forum.com/.
Why do you want to use the same primary key value for multiple tables?
Unless you have a really good reason for not following the rails
conventions then it is best to stick to them. Your life will be much
easier. Just set up the appropriate relationships between the models
in the normal way.
Colin
Are you sure? Trying to force rails away from its preferred
conventions is rarely fun. Do it the easy way and use the time saved
to indulge in something that is really fun :)
> It is just so natural to use the same primary key in this situation.
Why?
Colin
Well, it seems natural to me, and i often trust my senses :).
I have been playing with it in console for a few minutes now and
observing some fun and weird behavior:
i = Instructor.create
i.id # => 1
i.person_id # => nil
Instructor.find(1) # => NoMethodError: undefined method `eq' for
nil:NilClass ...
i=Instructor.find_by_person_id(1)
i.id # => nil
i.person_id # => 1
So far it seem to be possible to find ways around to make it work, but i
wonder if i am not making a philosophical mistake indeed, and if it will
not break in new versions of rails ...
This is some strange new use of the word fun, with which I am not familiar.
Colin
Also,
p=Person.create
m=p.create_member
i=p.create_instructor
work as expected now with setting identical values for p.id, m.id,
m.person_id, i.id, and i.person_id.
When an instructor with the value of id equal to p.id already exists,
i=p.create_instructor
triggers
ActiveRecord::StatementInvalid: SQLite3::ConstraintException: PRIMARY
KEY must be unique: ...
which is a desired behavior.
I will keep testing, and if i do not encounter something extremely
weird, i may stick to this...
Thank you.
The migration
class CreateInstructors < ActiveRecord::Migration
def self.up
create_table :instructors do |t|
t.primary_key :person_id
t.text :presentation
...
does not work (SQLite3::SQLException: table "instructors" has more than
one primary key: ... during migration),
but
class CreateInstructors < ActiveRecord::Migration
def self.up
create_table :instructors, :primary_key => "person_id" do |t|
t.primary_key :person_id
t.text :presentation
...
and
class CreateInstructors < ActiveRecord::Migration
def self.up
create_table :instructors, :primary_key => "person_id" do |t|
t.text :presentation
...
seem to have completely identical effect:-/.
if i have set_primary_key 'person_id':
class Instructor < ActiveRecord::Base
set_primary_key 'person_id'
...
end
does it mean that writing
class Person < ActiveRecord::Base
has_one :instructor, :primary_key => 'person_id'
end
would be redundant?
What is the purpose of :primary_key in has_one options, if one uses
set_primary_key ?
Thanks.
has_one :something, :primary_key => 'someone_id'
What is it for if the primary key has to be set with set_primary_key =>
'someone_id' ?
I removed my other post because i realized that in my situation the
primary key used for the association was in fact "id", so it was a bad
example.
Still, in your example, i do not understand the need for ":primary_key
=>":
Kendall Gifford wrote in post #989309:
> class User < ActiveRecord::Base
> set_table_name "tblUser"
> set_primary_key "UserID"
> has_many :comments, :primary_key => "UserID",
> :foreign_key => "PosterID"
> end
was it not working without it?
It seems redundant to write:
class Instructor < ActiveRecord::Base
set_primary_key 'person_id'
has_many :lessons, :primary_key => 'person_id'
...
end
It also does not seem to me to be strictly necessary to add to the
above:
class Lesson < ActiveRecord::Base
belongs_to :instructor, :primary_key => 'person_id'
...
end
However, i can philosophically understand the need for ":primary_key =>"
on the "belongs_to" side of association, it could serve to make this
side more independent from the "has_many" side, and avoid unexpected
behavior of Lesson if Instructor is broken ("set_primary_key
'person_id'" deleted).
It seems to me that Rails makes it possible to define and use only one
side of an association, without defining the other (otherwise the
":inverse_of =>" option probably wouldn't be useful).
I have not properly tested this situation with and without ":primary_key
=>", but so far it seems to work without, "set_primary_key 'person_id'"
seems to suffice for both sides.
So i will try to leave it like this...
P.S. the reason i am torturing Rails like that is that it also has a
convention that it should obey the human.
Seriously, i just want a nice and clear structure of my database, which
would be editable by hand (it is not going to be big), and to use Rails
just for a simple interface.