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...
On Dec 1, 11:32 pm, Peter Vandenabeele <[email protected]> wrote: > On Thu, Dec 1, 2011 at 10:59 PM, Erwin <[email protected]> wrote: > > 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... > > 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. > > 2) 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 -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.

