是否可以以递归方式保存Rails中的记录?

Lai*_*uan 9 activerecord ruby-on-rails

例如,user有一个list,list有很多items,我在控制器中有以下代码:

@user = User.new()
@list = List.new()
(1..10).each { |i| @list.items << (Item.new(:order => i)) }
@user.list = @list
Run Code Online (Sandbox Code Playgroud)

现在,如果我打电话@user.save,@list10 item秒将不会保存到数据库.我该如何重写这段代码?

inf*_*sed 10

通过设置适当的关联和验证,您可以确保在保存用户时,同时保存关联的列表和项目.此外,您可以确保在一个事务中保存所有内容,并且如果无法保存子记录,则将中止保存.

给定User,List和Item的以下模型定义

class User < ActiveRecord::Base
  belongs_to :list
  validates_associated :list
end

class List < ActiveRecord::Base
  has_many :items
  validates_associated :items
end

class Item < ActiveRecord::Base
  validates :name, presence: true
end
Run Code Online (Sandbox Code Playgroud)

调用user.save具有无效列表项的用户现在将返回false,并且不会保存任何记录.您可以查询user.errors以找出保存中止的原因.

user = User.new
list = user.build_list
list.items.build(name: nil) 
user.save # => false
user.errors.messages # => {:list=>["is invalid"]}
user.list.error.messages # => {:items=>["is invalid"]} 
Run Code Online (Sandbox Code Playgroud)

由于Item验证了名称的存在,因此项目的保存失败,并且没有保存任何记录.您在SQL日志中应该看到的内容如下:

(0.2ms)  BEGIN
(0.2ms)  ROLLBACK
Run Code Online (Sandbox Code Playgroud)

现在,如果所有记录都有效:

user = User.new
list = user.build_list(name: 'My List')
list.items.build(name: 'Widget')
user.save # => true
Run Code Online (Sandbox Code Playgroud)

ActiveRecord将以正确的顺序保存记录,以便设置foreign_keys.所有3个插入也包含在事务中:

(0.2ms)  BEGIN
SQL (0.3ms)  INSERT INTO `lists` (`name`) VALUES ('My list')
SQL (0.1ms)  INSERT INTO `items` (`list_id`, `name`) VALUES (4, 'Widget')
SQL (0.3ms)  INSERT INTO `users` (`list_id`) VALUES (4)
(0.3ms)  COMMIT
Run Code Online (Sandbox Code Playgroud)


Ada*_*lin 2

我想你的意思是@user.list = @list

之后,调用@user.save应该可以保存一切。