has_one(association_id, options = {}) public

Adds the following methods for retrieval and query of a single associated object: association is replaced with the symbol passed as the first argument, so has_one :manager would add among others manager.nil?.

  • association(force_reload = false) - returns the associated object. nil is returned if none is found.
  • association=(associate) - assigns the associate object, extracts the primary key, sets it as the foreign key, and saves the associate object.
  • association.nil? - returns true if there is no associated object.
  • build_association(attributes = {}) - returns a new object of the associated type that has been instantiated with attributes and linked to this object through a foreign key, but has not yet been saved. Note: This ONLY works if an association already exists. It will NOT work if the association is nil.
  • create_association(attributes = {}) - returns a new object of the associated type that has been instantiated with attributes, linked to this object through a foreign key, and that has already been saved (if it passed the validation).

Example: An Account class declares has_one :beneficiary, which will add:

  • Account#beneficiary (similar to Beneficiary.find(:first, :conditions => "account_id = #{id}"))
  • Account#beneficiary=(beneficiary) (similar to beneficiary.account_id = account.id; beneficiary.save)
  • Account#beneficiary.nil?
  • Account#build_beneficiary (similar to Beneficiary.new("account_id" => id))
  • Account#create_beneficiary (similar to b = Beneficiary.new("account_id" => id); b.save; b)

The declaration can also include an options hash to specialize the behavior of the association.

Options are:

  • :class_name - specify the class name of the association. Use it only if that name can’t be inferred from the association name. So has_one :manager will by default be linked to the Manager class, but if the real class name is Person, you’ll have to specify it with this option.
  • :conditions - specify the conditions that the associated object must meet in order to be included as a WHERE SQL fragment, such as rank = 5.
  • :order - specify the order in which the associated objects are returned as an ORDER BY SQL fragment, such as last_name, first_name DESC
  • :dependent - if set to :destroy, the associated object is destroyed when this object is. If set to :delete, the associated object is deleted without calling its destroy method. If set to :nullify, the associated object’s foreign key is set to NULL. Also, association is assigned.
  • :foreign_key - specify the foreign key used for the association. By default this is guessed to be the name of this class in lower-case and _id suffixed. So a Person class that makes a has_one association will use person_id as the default foreign_key.
  • :include - specify second-order associations that should be eager loaded when this object is loaded.
  • :as: Specifies a polymorphic interface (See #belongs_to).

Option examples:

  has_one :credit_card, :dependent => :destroy  # destroys the associated credit card
  has_one :credit_card, :dependent => :nullify  # updates the associated records foreign key value to NULL rather than destroying it
  has_one :last_comment, :class_name => "Comment", :order => "posted_on"
  has_one :project_manager, :class_name => "Person", :conditions => "role = 'project_manager'"
  has_one :attachment, :as => :attachable
Show source
Register or log in to add new notes.
September 25, 2008
2 thanks

Support for the option through

class Magazine < ActiveRecord::Base

  has_many :subscriptions

class Subscription < ActiveRecord::Base
  belongs_to :magazine
  belongs_to :user

class User < ActiveRecord::Base
  has_many :subscriptions
  has_one :magazine, :through => :subscriptions, :conditions => ['subscriptions.active = ?', true]
October 14, 2009
2 thanks

build_association deletes existing dependent record

Surprisingly (at least I was surprised), when an associated record exists, the build_association method immediately NULLs the foreign key in the database.

So if you write a singleton “new” action for the association in the obvious way (calling build_association), then just visiting the page will disconnect an existing associated record. This violates the principle that a GET request shouldn’t affect the database.

To avoid this, you can check for an existing association first, and redirect to the show action.

August 25, 2010 - (>= v2.3.8)
2 thanks

Undocumented :inverse_of option

Support for the :inverse_of option was backported to 2.3.6+.

Here’s the description from the original commit: http://github.com/rails/rails/commit/ccea98389abbf150b886c9f964b1def47f00f237

You can now add an :inverse_of option to has_one, has_many and belongs_to associations. This is best described with an example:

class Man < ActiveRecord::Base
  has_one :face, :inverse_of => :man

class Face < ActiveRecord::Base
  belongs_to :man, :inverse_of => :face

m = Man.first
f = m.face

Without :inverse_of m and f.man would be different instances of the same object (f.man being pulled from the database again). With these new :inverse_of options m and f.man are the same in memory instance.

Currently :inverse_of supports has_one and has_many (but not the :through variants) associations. It also supplies inverse support for belongs_to associations where the inverse is a has_one and it’s not a polymorphic.

April 27, 2009 - (>= v2.0.0)
0 thanks

has_one through belongs_to not working

code example:

class Company < ActiveRecord::Base
  has_many :route_lists

class RouteList < ActiveRecord::Base
  belongs_to :company
  has_many :routes

class Route < ActiveRecord::Base
  belongs_to :route_list
  has_one :company :through => :route_list

This creates an invalid SQL query, where the keys in the join between route and routelist are switched, when used as an include:

Routes.find :all, :conditions => ["companies.type = ?", "Account"], :include => :company

route_lists.route_list_id = route.id

instead of: route_lists.id = route.route_list_id