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).
  • :select - By default, this is * as in SELECT * FROM, but can be changed if, for example, you want to do a join but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will raise an error.
  • :through: Specifies a Join Model through which to perform the query. Options for :class_name and :foreign_key are ignored, as the association uses the source reflection. You can only use a :through query through a has_one or belongs_to association on the join model.
  • :source - Specifies the source association name used by has_one :through queries. Only use it if the name cannot be inferred from the association. has_one :favorite, :through => :favorites will look for a :favorite on Favorite, unless a :source is given.
  • :source_type - Specifies type of the source association used by has_one :through queries where the source association is a polymorphic belongs_to.
  • :readonly - If true, the associated object is readonly through the association.

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
  has_one :boss, :readonly => :true
  has_one :club, :through => :membership
  has_one :primary_address, :through => :addressables, :conditions => ["addressable.primary = ?", true], :source => :addressable
Show source
Register or log in to add new notes.
August 25, 2010 - (>= v2.3.8)
3 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
end

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

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.

September 25, 2008
2 thanks

Support for the option through

class Magazine < ActiveRecord::Base

  has_many :subscriptions
end

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

class User < ActiveRecord::Base
  has_many :subscriptions
  has_one :magazine, :through => :subscriptions, :conditions => ['subscriptions.active = ?', true]
end
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.

April 27, 2009
0 thanks

has_one through belongs_to not working

code example:

class Company < ActiveRecord::Base
  has_many :route_lists
end

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

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

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