what is a RoR best practice? match by id or different column?
I had a terrible morning. Lots of emails floating around about why things don't work. Upon investigating I found that there is a data mismatch which is causing errors.
Scenario
Customer
and Address
are two tables.
Customer
contains
class Customer < ActiveRecord::Base
has_one :address, :foreign_key => "id"
end
开发者_Python百科
Address
Contains
class Address < ActiveRecord::Base
belongs_to :customer, :foreign_key => "cid"
end
So the two tables match on id
which is the default and that column is auto incremented.
Problem on the edit Page we have some code like this.
params[:line1] = @customer.first.address.line1
It fails because no matching record is found for a customer in the address table. I don't know why this is happening. It seems that over time a lot of records did not get added to Address
table. Now problem is that when a new Customer
is added (say with id 500) the Address
will be added with some other id (say 425) ...now you don't know which address belongs to which customer.
Question
Being new to Rails, I am asking whether it is always considered good to create an extra column for joining of the records, rather than depending on the column that is automatically incremented? If I had a seperate column in Address
table where I would manually insert the recently added customers id then this issue would not have come up.
That has_one
-belongs_to
relationship should result in the "belonging" model having the key of the "having" model. Or, in other words, the :foreign_key
clause should be the same in both models.
If I have these:
class Customer < ActiveRecord::Base
has_one :address, :foreign_key => 'cid' # note foreign_key same as in Address
end
class Address < ActiveRecord::Base
belongs_to :customer, :foreign_key => 'cid' # note foreign_key same as in Customer
end
then I can do this:
>> cust = Customer.create(:name=>'Mr Custard')
+----+------------+
| id | name |
+----+------------+
| 1 | Mr Custard |
+----+------------+
1 row in set
>> add = cust.create_address(:line_1 => '42 Some Street', :line_2 => 'Some where')
+----+-----+----------------+------------+
| id | cid | line_1 | line_2 |
+----+-----+----------------+------------+
| 1 | 1 | 42 Some Street | Some where |
+----+-----+----------------+------------+
1 row in set
checking:
>> Customer.first.address
+----+-----+----------------+------------+
| id | cid | line_1 | line_2 |
+----+-----+----------------+------------+
| 1 | 1 | 42 Some Street | Some where |
+----+-----+----------------+------------+
1 row in set
>> Address.first.customer
+----+------------+
| id | name |
+----+------------+
| 1 | Mr Custard |
+----+------------+
and my database looks like this:
sqlite> select * from customers;
1|Mr Custard
sqlite> select * from addresses;
1|1|42 Some Street|Some where
(the nice table output for ActiveRecord results comes from Hirb, by the way)
The Rails' convention is for each table to have an auto-incrementing integer primary key column named id
and additionally—in your example—for the addresses
table to have a non auto-incrementing integer foreign key column named customer_id
. As the name implies, this holds the primary key value from the associated record in the customers
table.
If you follow these rules then there's no need to specify a :foreign_key
option on the associations.
精彩评论