Follow the law of Demeter
class Address < ActiveRecord::Base
belongs_to :customer end
class Customer < ActiveRecord::Base has_one :address has_many :invoices end
class Invoice < ActiveRecord::Base
belongs_to :customer end
# Views
<%= @invoice.customer.name %> <%= @invoice.customer.address.street %>
<%= @invoice.customer.address.city %>
<%= @invoice.customer.address.state %>
<%= @invoice.customer.address.zip_code %>
Law of Demeter: lays out the concept that an object can call methods on a related object but that it should not reach through that object to call a method on a third. In Rails, this could be summed up as “use only one dot.”
So we can write a method :
class Customer < ActiveRecord::Base
has_one :address has_many :invoices def street address.street end def city
address.city end def state address.state end
end
<%= @invoice.customer_name %>
<%= @invoice.customer_street %>
In addition, your public interface on Invoice has been polluted by methods that arguably have nothing to do with the rest of your interface for invoices.
Solution
Fortunately, Ruby on Rails includes a function that addresses the first concern. This method is the class-level delegate method. This method provides a shortcut for indicating that one or more methods that will be created on your object are actually provided by a related object. Using this delegate method, you can rewrite your exam- ple like this:
class Customer < ActiveRecord::Base
has_one :address has_many :invoices delegate :street, :city, :state, :zip_code, :to => :address
end
class Invoice < ActiveRecord::Base belongs_to :customer delegate :name, :street, :to => :customer, :prefix => true
end