开发者

one to one join with rails

开发者 https://www.devze.com 2022-12-17 08:04 出处:网络
I am new with rails and trying to understand its :has_many and :belongs_to functionalities. If I have 3 tables: Customers, Physicians, Addresses

I am new with rails and trying to understand its :has_many and :belongs_to functionalities.

If I have 3 tables: Customers, Physicians, Addresses

Each customer and each physician will have one address. So it is a one-to-one relationship.

customer_id and physician_id will match address_id

So if I want 开发者_运维知识库address of a customer with id 3. I'd say

select * from customer, addresses 
where customer_id = 3 and customer.customer_id = addresses.address_id

How will I translate this into rails code?

I'll have 3 models Customer, Physician, Address

But I am not sure as to what the relationship be? How will i translate the above query to rails find function?

Customer.find (:all, ......?


I wouldn't share the PK between the tables. What if you have Physician (id = 1), Customer (id = 1). Then who gets Address (id = 1). This is the schema I'd propose

Address
-------
id

Customer
--------
id
address_id

Physician
---------
id
address_id

Then, to bind in your class.

class Physician < ActiveRecord::base
  belongs_to :address
end

class Customer < ActiveRecord::base
  belongs_to :address
end

class Address < ActiveRecord::base
  has_one :physician
  has_one :customer

  def customer_address?
    !customer.nil?
  end

  def physician_address?
    !physician.nil?
  end

end

It may look a little backwards, but look at the FK relationships. Address is referenced by Physician and Customer. Not the other way around.

The docs will say that you almost never want a has_one relationship. I use them, but only when I reinforce them with unique IDs in the database. So make sure that you add a migration like the following.

self.up
  add_index :customers, :address_id, :unique => true
  add_index :physicians, :address_id, :unique => true
end

Now, you know that a customer will only ever match to a single address.


Just quickly... you meant in your SQL query "customer.address_id = addresses.address_id" right?

When you put

has_one :address

into the Customer model and

belongs_to :customer

in the Address model, you do the same find as usual, but you can refer to it like:

@cust = Customer.find(params[:id])
street = @cust.address.street
city = @cust.address.city

and so on... check out http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html where it says "Is it a belongs_to or has_one association?" for more info.


Let's recap some OO principles on this one, as it will help with these answers. Consider:

  1. What is the benefit of having all of the addresses in one table?
  2. What is the benefit of having customers and physicians separated? Depending on what you're trying to do, these answers may vary.

In the most likely case, you're trying to model a customer's relationship to their (one? many?) physicians. The customer has a home address and the physician has an office address. And this illustrates one of the first outcomes - that the customer addresses and physician addresses are different. Consider the case where you dump the addresses, or sort them, or do something with them - do you care that both types of addresses are mixed together? If so, they are really two separate entities in your system. Separate them into two tables and you're done.

In a less-likely case, you don't really care about the difference between customers and physicians, only their addresses. Perhaps the association between these classes and their addresses is meant to help to scope the address? You explicitly want the ability to dump the addresses and do something with them, regardless of whether they're for the customer or physician. In any case, the Customer and Physician classes can be combined, since you don't care about the difference.

If you want to make all of thise more object oriented, consider inheritance. You might consider a base class (Person?) for the Customer/Physician which would bring together the common attributes and behaviours (including the association to your Address class) into one entity. And/or consider a base class for the CustomerAddress/PhysicianAddress classes, which implements the common attributes and behaviours (including the association to your Person class) into one entity. You might even consider Rails STI as a nice lightweight and ActiveRecord-supported way to get this done nice and clearly.

0

精彩评论

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

关注公众号