Итак, у вас есть два вопроса.Первый (хотя второй в вашем вопросе) - «как создать и сохранить дочерний объект вместе с родительским объектом за один шаг».Это общий шаблон и выглядит примерно так:
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, методе, говорится в Руководстве по валидации .
Надеюсь, что это полезно!