Rails 3:对象的验证

时间:2013-10-11 07:16:09

标签: ruby-on-rails-3 activerecord

我正在通过控制器创建一个对象。 Foo有很多Bar个。 Bar模型验证其必须具有Foo才能生效。

foo.rb模型中:

has_many: bars

bar.rb模型中:

validates_presence_of :foo
belongs_to: foo

foo_controller.rb

@foo = Booking.new(params[:foo]) # this has all the params needed to make a Foo.
@foo.create_bars(params[:bars])

foo.rb模型中:

def create_bars(bars)
    bars.each do |t|
      bar = Bar.create({name: name, email: email, foo: foo})
      bar.foo = self
      self.bars << bar
      bar.save
      puts self.bars.to_s
    end
  end

puts self.bars.to_s

这听起来应该是非常基本的东西,但由于db中不存在foo,ActiveRecord是否认为它是零,这就是为什么它不能保存?我怎样才能正确写出来?

3 个答案:

答案 0 :(得分:2)

也许试试这个:

def create_bars(bars)
  bars.each do |t|
    self.bars << Bar.new({name: t[:name], email: t[:email]})
  end
end

&LT;&LT;用于活动记录对象的运算符自动设置关联。

不要忘记在模型中添加has_many:foos和belongs_to:bar。

答案 1 :(得分:1)

我先回答这一部分:

  

这听起来应该是非常基本的东西,但是从那以后   数据库中不存在foo,ActiveRecord认为它是否为零,   这就是为什么它不能保存?我怎样才能正确写出来?

不完全。验证不依赖于数据库中的任何内容,它只是在持久化之前检查模型中是否存在指定的字段(或依赖对象)。 create方法是一种快捷方式,它不仅初始化ActiveModel对象,还同时尝试将其保存在数据库中。您的验证失败,因为您在设置foo对象的bar字段之前调用此方法。

可以在这个实例中通过在你的场景中传递create来技术上使用foo: self,但坦率地说,我会在@ pablopablo89的答案中使用这一部分。如果您这样做,当您保存Foo时,所有Bar对象也将被保存。

此外,用于创建.create个对象的Bar方法很危险,因为您可以立即保留Bar个独立于父Foo的对象,如果出于某种原因您的Foo无法保存(未通过其他验证等),最终会出现一堆孤立的Bar个对象,无法独立于Foo删除它们(I')我对你的系统实际工作方式做了一些假设。假设这是您系统的反映,您要记住的目标是一个对象及其所有依赖项都保存在一个原子操作中。如果一个失败,它们都会失败,并提醒用户。

更一般地回答这个问题,正如@phoet在评论中指出的那样,改变表单和使用accepts_nested_attributes_for方法可能会好得多。这是link to the rails documentation

Foo模型中,添加第accepts_nested_attributes_for :bars行,然后在表单中使用fields_for,如下所示:

<%= form_for @foo do |f| %>
    ...other stuff...
    <%= f.fields_for :bars do |f_bar| %>
       ... bar-related stuff ...

提交的参数映射将返回:foo键中所有与栏相关的内容,以便创建Foo对象和所有相关{{1}一次性对象。在这种情况下,Bar也可以使用,但我仍然倾向于单独create.new,但由您决定。

关于如何使用.save

This link也可能会有所帮助。

答案 2 :(得分:0)

Booking.new只是初始化一个对象。为了让foo存在,你需要保存它。保存后,创建条形对象时的验证将通过,并且应创建对象。希望这应该有用