Rails: заставляет пользователя создавать дочерний объект перед сохранением родителя - PullRequest
3 голосов
/ 21 октября 2011

Я новичок в Ruby on Rails. В настоящее время у меня есть следующая проблема: у меня есть класс Game, в котором чередуются картинки и предложения. Я хочу, чтобы пользователь, который создает новый Game, дал одно начальное изображение ИЛИ предложение. Если он этого не сделает, я бы не хотел сохранять вновь созданную игру в базу данных.

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

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

  [...]
end

Мой подход состоял в том, что на / games / new пользователь должен сначала указать одно рисование или одно предложение, но я не уверен, как это применить, особенно как создавать и сохранять дочерний объект вместе с родительским. объект за один шаг.

1 Ответ

5 голосов
/ 21 октября 2011

Итак, у вас есть два вопроса.Первый (хотя второй в вашем вопросе) - «как создать и сохранить дочерний объект вместе с родительским объектом за один шаг».Это общий шаблон и выглядит примерно так:

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

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

Тогда, скажем, views/games/new.html.erb вы можете иметь что-то вроде этого:

<%= 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, который выглядит примерно так:

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

И, наконец, в контроллере, который получает эти params:

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

Это очень очень высокий взгляд на то, что вы будете делать.Вложенные атрибуты имеют свой собственный раздел в документации .

Другой ваш вопрос - как это обеспечить.Для этого вам нужно написать несколько пользовательских проверок.Есть два способа сделать это.Самый простой способ - использовать validate, например:

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

Другой метод - создание пользовательского класса валидатора, который находится в другом файле.Это особенно полезно, если вам нужно выполнить много пользовательских проверок или если вы хотите использовать одни и те же пользовательские проверки для нескольких классов.Об этом, а также об одном методе, er, методе, говорится в Руководстве по валидации .

Надеюсь, что это полезно!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...