开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜