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.

Reply via email to