Я использую accepts_nested_attributes_for в одной из моих моделей Rails, и я хочу сохранить дочерние элементы после создания родителя.
Форма работает отлично, но проверка не выполняется. Для простоты представьте себе следующее:
class Project < ActiveRecord::Base
has_many :tasks
accepts_nested_attributes_for :tasks
end
class Task < ActiveRecord::Base
belongs_to :project
validates_presence_of :project_id
validates_associated :project
end
И я бегу:
Project.create!(
:name => 'Something',
:task_attributes => [ { :name => '123' }, { :name => '456' } ]
)
При сохранении модели проекта проверка не выполняется в задачах, потому что у них нет project_id (так как проект не был сохранен).
Кажется, что Rails выполняет следующий шаблон:
- Проверить проект
- Подтвердить задачи
- Сохранить проект
- Сохранить задачи
Образец должен быть:
- Проверить проект
- On Pass: Сохранить проект и продолжить...
- Подтвердить задачи
- On Pass: Save Tasks
- В случае сбоя: удалить проект (возможно, откат)
Итак, мой вопрос сводится к следующему: Как я могу получить Rails для запуска метода project_id = (или project =) и проверки для дочерних элементов (задач) ПОСЛЕ того, как родительский (проект) был сохранен, но НЕ сохраняет родителя ( проект), если какой-либо ребенок (задача) недействителен?
Любые идеи?
Ответ 1
Используйте этот ответ для Rails 2, иначе см. ниже ответ :inverse_of
Вы можете обойти это с помощью не проверки для project_id, если соответствующий проект действителен.
class Task < ActiveRecord::Base
belongs_to :project
validates_presence_of :project_id, :unless => lambda {|task| task.project.try(:valid?)}
validates_associated :project
end
Ответ 2
Используйте :inverse_of
и validates_presence_of :parent
. Это должно исправить вашу проблему проверки.
class Dungeon < ActiveRecord::Base
has_many :traps, :inverse_of => :dungeon
end
class Trap < ActiveRecord::Base
belongs_to :dungeon, :inverse_of => :traps
validates_presence_of :dungeon
end
http://apidock.com/rails/ActiveModel/Validations/HelperMethods/validates_presence_of
https://github.com/rails/rails/blob/73f2d37505025a446bb5314a090f412d0fceb8ca/activerecord/test/cases/nested_attributes_test.rb
Ответ 3
Проверяйте только отношения, а не идентификатор:
class Task < ActiveRecord::Base
belongs_to :project
validates_presence_of :project
end
Как только ассоциация будет заполнена, ActiveRecord будет считать, что проверка прошла успешно, независимо от того, сохранена ли модель. Вы также можете изучить автосохранение, чтобы гарантировать, что проект задачи всегда сохраняется:
class Task < ActiveRecord::Base
belongs_to :project, :autosave => true
validates_presence_of :project
end
Ответ 4
К сожалению, ни одно из приведенных выше предложений не работает для меня с Rails 2.3.5.
В моем случае проект в задаче всегда равен нулю, если оба они созданы с использованием вложенных атрибутов. Только если я удалю validates_presence_of, создание пройдет успешно. unit test и журнал показывают, что все создано правильно.
Итак, теперь я хотел бы добавить ограничения к БД вместо Rails, поскольку в первую очередь это кажется более надежным.
Ответ 5
Вы можете просто создать проект и добавить только проекты, если он пройдет проверку:
tasks = params.delete(:task_attributes)
if Project.create(params)
Project.update_attributes(:task_attributes => tasks)
end
Чао
Ответ 6
В отличие от того, что предлагает биго, не всегда приемлемо сначала сохранить родительский объект, а затем детей. Обычно вы хотите убедиться, что все объекты проверяются до их сохранения. Это дает пользователю возможность повторно редактировать форму ввода и исправлять любые ошибки.
Описанная вами проблема будет исправлена в Rails 3.0. Я бы разместил ссылку на билет Lighthouse, но stackoverflow.com не разрешает это, потому что я новый пользователь (#fail). Но пока вы можете использовать плагин " parental_control", который исправит вашу "ошибку".