强制用户在保存父对象之前创建子对象

强制用户在保存父对象之前创建子对象

本文介绍了Rails:强制用户在保存父对象之前创建子对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是Ruby on Rails的初学者.当前,我遇到以下问题:我有一个类Game,该类具有由图片和句子组成的数组.我希望创建新Game的用户必须给出一个起始图片或句子.如果他不这样做,我不想将新创建的游戏保存到数据库中.

I am a beginner at Ruby on Rails. Currently, I have the following problem: I have a class Game that has an array of pictures and sentences alternating. I want that a user who creates a new Game is required to give one starting picture OR sentence. If he doesn't do so I'd like to not save the newly created game to the data base.

class Game < ActiveRecord::Base
  has_many :sentences
  has_many :paintings

  validates_inclusion_of :starts_with_sentence, :in => [true, false]

  [...]
end

我的方法是,在/games/new上,用户必须先给出一幅画或一句话,但是我不确定如何执行此操作,尤其是如何与父级一起创建和保存子级对象对象只需一步即可.

My approach was that on /games/new, the user has to give either one painting or one sentence to begin with, but I am unsure how to enforce this, especially how to create and save a child object along with the parent object in one step.

推荐答案

因此,您有两个问题.第一个(虽然是问题中的第二个)是如何在一个步骤中创建和保存子对象以及父对象".这是一种常见的模式,看起来像这样:

So you've got two questions. The first (though second in your question) is "how to create and save a child object along with the parent object in one step." This is a common pattern and looks something like this:

class Game < ActiveRecord::Base
  has_many :sentences
  has_many :paintings

  accepts_nested_attributes_for :sentences, :paintings # <-- the magic
end

然后输入views/games/new.html.erb,您可以输入以下内容:

Then in, say, views/games/new.html.erb you can have something like this:

<%= form_for :game do |f| %>
  <%= label :name, "Name your game!" %>
  <%= text_field :name %>

  <%= fields_for :sentence do |s| %>
    <%= label :text, "Write a sentence!" %>
    <%= text_field :text %>
  <% end %>

  <%= fields_for :painting do |s| %>
    <%= label :title, "Name a painting!" %>
    <%= text_field :title %>
  <% end %>
<% end %>

提交此表单后,Rails将解释POST参数,最后得到一个params对象,看起来像这样:

When this form is submitted Rails will interpret the POST parameters and you'll end up with a params object that looks something like this:

# params ==
{ :game => {
    :name     => "Hollywood Squares",
    :sentence => {
      :text => "Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo."
    },
    :painting => {
      :title => "Les Demoiselles d'Avignon"
    }
  }
}

最后,在接收那些params的控制器中:

And finally, in the controller that receives those params:

def create
  new_game = Game.create params[:game] # magic! the associated Sentence and/or
end                                    # Painting will be automatically created

这是对您要执行的操作的非常非常高级的了解.嵌套属性在文档中的部分中.

That's a very very high-level peek at what you'll be doing. Nested attributes have their very own section in the docs.

您的另一个问题是如何执行此操作.为此,您需要编写一些自定义验证.有两种方法可以做到这一点.最简单的方法是使用validate,例如:

Your other question is how to enforce this. To do that you'll need to write some custom validations. There's two ways to do this. The simplest way is with validate, e.g.:

class Game < ActiveRecord::Base
  # ...

  validate :has_sentence_or_painting  # the name of a method we'll define below

  private # <-- not required, but conventional

  def has_sentence_or_painting
    unless self.sentences.exists? || self.paintings.exists?
      # since it's not an error on a single field we add an error to :base
      self.errors.add :base, "Must have a Sentence or Painting!"

      # (of course you could be much more specific in your handling)
    end
  end
end

另一种方法是创建一个驻留在另一个文件中的自定义验证器类.如果您需要进行大量的自定义验证,或者要在多个类上使用相同的自定义验证,则此功能特别有用. 《 Validations Rails指南》 均涵盖了此方法以及一个或多个方法.

The other method is creating a custom validator class which lives in another file. This is particularly useful if you need to do a lot of custom validations or if you want to use the same custom validations on several classes. This, along with the single method, er, method, are both covered in the Validations Rails Guide.

希望有帮助!

这篇关于Rails:强制用户在保存父对象之前创建子对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-24 00:17