Search code examples
ruby-on-railssyntaxvirtualrelationships

"Virtual Relationships" in Rails


I'm trying to do a "virtual relationship" (what I call it - don't know if there's a real term for it) in Rails. Here's one that I have that is definitely working: Address belongs_to Business and Business has_many Addresses. Addresses have a 'category' column: either Mailing or Physical. In theory, a business could have any number of each type, but in practice they have exactly one of each. So my models look like this:

class Address < ActiveRecord::Base
  belongs_to :business
end

class Business < ActiveRecord::Base
  has_many :addresses
  has_one  :physical_address, :class_name => 'Address', :conditions => ["category = ?", "Physical"]
  has_one  :mailing_address, :class_name => 'Address', :conditions => ["category = ?", "Mailing"]
end

Thus, I have two "virtual" has_one's, so that I can conveniently access either one (as business.physical_address or business.mailing_address) without having to do the work of separating them myself.

Now I'm trying to do something similar, but with a has_many :through. Here's my new scenario. I have a simple many-to-many relationship with a join. Let's say A has many J's, B also has many J's, and J belongs_to both A and B. However, A also has_many B's through J. So I can access them as a.bs.

However, the entries in B also have a 'category'. So as with the Business/Address example above, I want to have "virtual" has-one/many-through relationships in A, so I don't have to manually separate the B's by category. I tried something like this (assuming A's have exactly one B with category='Type 1'):

class A < ActiveRecord::Base
  has_many :js
  has_many :bs, :through => js
  has_one  :b_type1, :class_name => 'B', :through => :js, :conditions => ["category = ?", "Type 1"]
end

However, when I do a find on A's, the resulting objects do not have a b_type1 property in them.

Is it even possible to do what I'm trying to do?? Any help is appreciated.

Edit: I am needing this to be serialized to an Adobe Flex frontend (using the RestfulX framework). According to this thread, I can't use just a method as @Andrew suggests below because the resulting object will not get properly serialized without some heavy-duty effort.


Solution

  • The has_one association you wrote should work exactly as you want it, however Rails won't be able to guess the field from :b_type1.

    Just as you explicitly specified the class name, try specifying the source:

    has_one :b_type1, :class_name => 'B', :through => :js, :source => bs, :conditions => ["category = ?", "Type 1"]
    

    I tested a similar finder and it worked as you would expect it to.