1

Assuming I have something like this:

# Schema:
DB.create_table :transactions do
    primary_key :id
    foreign_key :card_id, :cards
    Integer     :amount
end
DB.create_table :cards do
    primary_key :id
    foreign_key :transaction_id, :transactions
    Intger      :number
end

# Models:
class Transaction < Sequel::Model
    one_to_one :card
end
class Card < Sequel::Model
    one_to_one :transaction
end

How do I make this work, such that it saves both trans, card, and their respective associations?

trans = Transaction.new(:amount => 100)
card = Card.new(:number => 4000500060007000)
trans.card = card
trans.save

As it stands, this doesn't work because card isn't saved first, and Sequel throws a "no primary key" error. If I save the card first, it won't get the transaction's id.

Basically, I'm trying to avoid this:

# Save without associations first, but this will assign primary keys
trans.save
card.save

# Now, manually create associations
trans.card = card
card.trans = trans

# Re-save again, this time with associations
trans.save
card.save
Arman H
  • 5,488
  • 10
  • 51
  • 76

1 Answers1

3

You may want to try and change the association type to something more like:

# Schema:
DB.create_table :transactions do
    primary_key :id
    Integer     :amount
end
DB.create_table :cards do
    primary_key :id
    foreign_key :transaction_id, :transactions
    Integer      :number
end

# Models:
class Transaction < Sequel::Model
    one_to_many :card
end
class Card < Sequel::Model
    one_to_one :transaction
end

Now you create as:

trans = Transaction.new(:amount => 100)
trans.save
trans.add_card(:number => 4000500060007000)

This will allow for all the same options as well as permitting (but certainly not requiring) a transaction to be split across multiple cards.

Pedro Nascimento
  • 13,136
  • 4
  • 36
  • 64
Patrick Hurley
  • 381
  • 1
  • 5
  • Thanks, but I'm looking for a solution that doesn't change the object associations from `1:1` to `1:many`. – Arman H Jul 05 '13 at 18:48
  • Why not just combine the table? If the relation is 1:1 and 1:1, then there is no reason to not create a table with both sets of columns -- it will represent the exact same data. – Patrick Hurley Jul 06 '13 at 19:25
  • This example is trivial, and I used it to illustrate the problem. The actual models are much more complicated. – Arman H Jul 06 '13 at 23:31
  • I assumed so, but in every case a completely reflexive 1:1 relationship is the same as using a single table. – Patrick Hurley Jul 07 '13 at 02:02
  • Though this answer didn't solve my problem, I've awarded the bounty for the effort and providing useful information. – Arman H Jul 10 '13 at 03:40
  • @ArmanH, I think it's considered a mistake to set up foreign keys on both tables -- there's no good way to write the code the way you want because that schema is flawed. It allows for the possibility of data inconsistency and it is superfluous -- one foreign key is completely sufficient. Patrick's solution is the right one. – Ben Lee Jul 10 '13 at 05:33
  • See http://stackoverflow.com/questions/9420916/onetoone-unidirectional-and-bidirectional -- as the accepted answer there explains, a 1-to-1 relationship and a 1-to-many relationship share the same schema structure, they are just used differently in the code. – Ben Lee Jul 10 '13 at 05:34
  • 1
    And the Sequel docs themselves at http://sequel.rubyforge.org/rdoc/files/doc/association_basics_rdoc.html say "If you want to setup a 1-1 relationship between two models, you have to use many_to_one in one model, and one_to_one in the other model" and also "the one_to_one association can be thought of as a subset of the one_to_many association, but where there can only be either 0 or 1 records in the associated table." – Ben Lee Jul 10 '13 at 05:35
  • 1
    @BenLee, thanks for the input. The 1:1 example from Sequel's docs does not work for me. If I only specify `one_to_one` on the Transaction model and nothing in Card, then `add_card` or `add_trans` methods are missing from both models, and I cannot do something like `card.transactions`. – Arman H Jul 10 '13 at 19:48