0

I'm using Ruby 1.9.3 and RoR 3.20.

I am looking for a way to insert into two different tables, the parent and then child tables, in a single commit.

Currently, ActiveRecord generates code like this:

  (0.0ms)  BEGIN
 SQL (1.0ms)  INSERT INTO `parent` (`datefield`) VALUES ('2015-03-12 13:23:22')
(81.0ms)  COMMIT
(1.0ms)  BEGIN
SQL (1.0ms)  INSERT INTO `child` ( `parent_id`, `textfield`) VALUES ('1', 'text')
(73.0ms)  COMMIT

and the ruby code that causes this is:

fo = Parent.create!(datefield: '2015-03-12 13:23:22')
    fo.child.create(textfield: 'text')

I use create! so that if it fails it will bail out and won't try to create the record for the child table which will then also fail because of foreign key constraints, but I would prefer that this interaction be handled by a database transaction.

I looked at this thread which has relevant info posted in the answer and comments but I'm hoping something has changed in the past few years since that question was asked? link Any assistance is appreciated.

Community
  • 1
  • 1
Topher
  • 1,011
  • 11
  • 19

2 Answers2

1

Simply wrap your creation-code-lines in a transaction.

ActiveRecord::Base.transaction do
  fo = Parent.create!(qprocess: 'SidekiqFailover')
  fo.childs.create(textfield: 'text')
end

Since your models inherit from ActiveRecord::Base, you could alternatively do the following:

Parent.transaction do
  # code
end

Also, with the proper associations and nested attributes set up, you would be better off doing something like this:

Parent.transaction do
  fo = Parent.new(qprocess: 'SidekiqFailover')
  fo.childs.new(textfield: 'text')
  fo.save!
end
SHS
  • 7,651
  • 3
  • 18
  • 28
  • in your last example, will the object `fo` be accessible outside of this transaction? So after the end, there's something that uses `fo`, does that need to be inside the `do .. end` even though it doesn't actually have anything to do with that transaction anymore and is trying to access information inside fo? – Topher Mar 13 '15 at 09:15
  • only if you declare it outside the transaction block. you could do `fo = nil; Parent.transaction{ stuff }; use_fo` – SHS Mar 13 '15 at 10:03
0

You should use nested model form instead of creating you own parent child record. It will automatically undo transaction if parent record failed to create.

Also you don't need to write two create operation in your code it will automatically handle. No need to add separate nested model gem it already there in rails 3. If not there is link for nested model form link here.

Here is a helpful link.

Jan Klimo
  • 4,643
  • 2
  • 36
  • 42
Dipak Gupta
  • 7,321
  • 1
  • 20
  • 32