one-to-one relationship

Is it wrong to use a beings_to on both side of a one-to-one association ?

User belongs_to :account so I have an account_id field

Account belongs_to :owner, :class_name => 'User', :foreign_key => 'user_id'

I can get user.account and account.owner It runs, but I wonder about any collateral effect...

thanks for your feedback

I think it’s fine.

Best Regards,

Everaldo

Which one do you create first? What foreign key value does it get? Do you always do the create/create/update in a transaction?

Do you ever (ever!) have one without the other?

class User < ActiveRecord::Base

has_one :account

end

class Account < ActiveRecord::Base

belongs_to :owner, :class_name => ‘User’, :foreign_key => ‘user_id’

end

I think that current versions of ActiveRecord have the right default for the foreign key (which is the _id after the class name rather than the association name), but specifying it works just fine, of course.

-Rob

Rob Biedenharn

Rob@AgileConsultingLLC.com http://AgileConsultingLLC.com/

rab@GaslightSoftware.com http://GaslightSoftware.com/

I don’t like it (if I understand correctly that you have both

in users table account_id

in accounts table user_id)

  1. This code expresses the 1-on-1 link between

a user and his associated account 2 times

(user.account_id points to account.id and

account.user_id point to user.id).

So, there is a chance that the 2 links go out of sync.

  1. You will always need 3 database writes to save

a pair of a user and an account.

If you did:

class User

belongs_to :account

end

class Account

has_one :user

end

you could write

account = Account.new(params[:account])

user = account.build_user(params[:user])

account.save # handle the return value

and this will do all that is required (with 2 database writes,

first the account, which will render the account.id and then

user will will be saved with user.account_id = account.id).

But with the original code (with 2 belongs_to associations),

I think you will need to do 3 writes:

  • account.save (#=> account.id)

  • user.save (with user.account_id = account.id)

  • a second account.save (for updating account.user_id = user.id)

I fail to see the advantage over a symmetric belongs_to , has_one

relationship.

Also check out the advantages of the inverse_of

class User

belongs_to :account, :inverse_of => :user

end

class Account

has_one :user, :inverse_of => :account

end

This will make sure the user.account is known before the save.

With the :inverse_of, this is the case:

$ rails c

Loading development environment (Rails 3.1.1)

001:0> u = User.new(:name => “peter”)

=> #<User id: nil, name: “peter”, account_id: nil, created_at: nil, updated_at: nil>

002:0> a = u.build_account(:number => “123”)

=> #<Account id: nil, number: “123”, created_at: nil, updated_at: nil>

003:0> a.user

=> #<User id: nil, name: “peter”, account_id: nil, created_at: nil, updated_at: nil>

004:0> u.save

(0.4ms) BEGIN

SQL (50.1ms) INSERT INTO “accounts” (“created_at”, “number”, “updated_at”) VALUES ($1, $2, $3) RETURNING “id” [[“created_at”, Thu, 01 Dec 2011 22:24:16 UTC +00:00], [“number”, “123”], [“updated_at”, Thu, 01 Dec 2011 22:24:16 UTC +00:00]]

SQL (1.6ms) INSERT INTO “users” (“account_id”, “created_at”, “name”, “updated_at”) VALUES ($1, $2, $3, $4) RETURNING “id” [[“account_id”, 1], [“created_at”, Thu, 01 Dec 2011 22:24:16 UTC +00:00], [“name”, “peter”], [“updated_at”, Thu, 01 Dec 2011 22:24:16 UTC +00:00]]

(0.9ms) COMMIT

=> true

Without the inverse_of relations, this is the result:

$ rails c

Loading development environment (Rails 3.1.1)

001:0> u = User.new(:name => “peter”)

=> #<User id: nil, name: “peter”, account_id: nil, created_at: nil, updated_at: nil>

002:0> a = u.build_account(:number => “123”)

=> #<Account id: nil, number: “123”, created_at: nil, updated_at: nil>

003:0> a.user

=> nil

004:0> # the “back link is only known AFTER the save to db and a reload :-/”

005:0* ^C

005:0> u.save

(0.4ms) BEGIN

SQL (16.1ms) INSERT INTO “accounts” (“created_at”, “number”, “updated_at”) VALUES ($1, $2, $3) RETURNING “id” [[“created_at”, Thu, 01 Dec 2011 22:28:35 UTC +00:00], [“number”, “123”], [“updated_at”, Thu, 01 Dec 2011 22:28:35 UTC +00:00]]

SQL (1.3ms) INSERT INTO “users” (“account_id”, “created_at”, “name”, “updated_at”) VALUES ($1, $2, $3, $4) RETURNING “id” [[“account_id”, 2], [“created_at”, Thu, 01 Dec 2011 22:28:35 UTC +00:00], [“name”, “peter”], [“updated_at”, Thu, 01 Dec 2011 22:28:35 UTC +00:00]]

(0.8ms) COMMIT

=> true

006:0> a.user

=> nil

007:0> a.reload

Account Load (1.4ms) SELECT “accounts”.* FROM “accounts” WHERE “accounts”.“id” = $1 LIMIT 1 [[“id”, 2]]

=> #<Account id: 2, number: “123”, created_at: “2011-12-01 22:28:35”, updated_at: “2011-12-01 22:28:35”>

008:0> a.user

User Load (1.0ms) SELECT “users”.* FROM “users” WHERE “users”.“account_id” = 2 LIMIT 1

=> #<User id: 2, name: “peter”, account_id: 2, created_at: “2011-12-01 22:28:35”, updated_at: “2011-12-01 22:28:35”>

009:0> # work-around (when inverse_of is not available)

010:0* ^C

010:0> u3 = User.new(:name => “peter”)

=> #<User id: nil, name: “peter”, account_id: nil, created_at: nil, updated_at: nil>

011:0> a3 = u3.build_account(:number => ‘456’, :user => u3)

(0.4ms) BEGIN

(0.3ms) COMMIT

=> #<Account id: nil, number: “456”, created_at: nil, updated_at: nil>

012:0> a3.user

=> #<User id: nil, name: “peter”, account_id: nil, created_at: nil, updated_at: nil>

013:0>

HTH,

Peter

Kad Kerforn wrote in post #1034622:

Is it wrong to use a beings_to on both side of a one-to-one association ?

User belongs_to :account so I have an account_id field

Account belongs_to :owner, :class_name => 'User', :foreign_key => 'user_id'

I can get user.account and account.owner It runs, but I wonder about any collateral effect...

thanks for your feedback

belongs_to should be on the side of a one-to-one association that contains the foreign key (same as a one-to-many).

The other side (the side without a foreign key should use has_one NOT belongs to.

User has_one :account

Account belongs_to :owner, :class_name => 'User', :foreign_key => 'user_id'

Or you could use the standard conventions:

Account belongs_to :user

Kad Kerforn wrote in post #1034622:

Is it wrong to use a beings_to on both side of a one-to-one

association ?

User

belongs_to :account so I have an account_id field

Account

belongs_to :owner, :class_name => ‘User’, :foreign_key => ‘user_id’

I can get user.account and account.owner

It runs, but I wonder about any collateral effect…

thanks for your feedback

belongs_to should be on the side of a one-to-one association that

contains the foreign key (same as a one-to-many).

The other side (the side without a foreign key should use has_one NOT

belongs to.

I think I didn’t thought enough before reply. =)

Good arguments, guys!

Thanks ... it runs , but as mentioned it has some side effects.... even if I cannot have one side wo the other one ... learn a lot about collateral effects...

Thanks ... it runs , but as mentioned it has some side effects.... even if I cannot have one side wo the other one ... learn a lot about collateral effects...

Thanks ... it runs , but as mentioned it has some side effects.... even if I cannot have one side wo the other one ... learn a lot about collateral effects...

Thanks ... it runs , but as mentioned it has some side effects.... even if I cannot have one side wo the other one ... learn a lot about collateral effects...

Got a clear understanding on what to do and not to do even if it works ...