method

has_one

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 and 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 from which the associated object will be picked at the top. Specified as
     an "ORDER BY" sql fragment, such as "last_name, first_name DESC"
    
  • :dependent - if set to :destroy (or true) 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 foriegn 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

3Notes

Support for the option through

RobinWu · Sep 25, 20082 thanks

=== 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

build_association deletes existing dependent record

wsmith67 · Oct 14, 20092 thanks

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.

has_one through belongs_to not working

THAiSi · Apr 27, 2009

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