has_one
- 1.0.0 (0)
- 1.1.6 (5)
- 1.2.6 (7)
- 2.0.3 (1)
- 2.1.0 (38)
- 2.2.1 (14)
- 2.3.8 (7)
- 3.0.0 (14)
- 3.0.9 (-6)
- 3.1.0 (5)
- 3.2.1 (4)
- 3.2.8 (0)
- 3.2.13 (0)
- 4.0.2 (-23)
- 4.1.8 (4)
- 4.2.1 (27)
- 4.2.7 (0)
- 4.2.9 (0)
- 5.0.0.1 (5)
- 5.1.7 (3)
- 5.2.3 (5)
- 6.0.0 (3)
- 6.1.3.1 (19)
- 6.1.7.7 (0)
- 7.0.0 (26)
- 7.1.3.2 (33)
- 7.1.3.4 (0)
- What's this?
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
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.
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
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.
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