2009-06-01 4 views
69

Я использую accepts_nested_attributes_for в одной из моих моделей Rails, и я хочу сохранить детей после создания родителя.accepts_nested_attributes_for не удалось выполнить проверку дочерней ассоциации

Форма работает отлично, но проверка не выполняется. Для простоты представим себе следующее:

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 будет по следующей схеме:

  • Validate проекта
  • Validate Задачи
  • Сохранить проект
  • Сохранить Задачи

Схема должна быть:

  • Validate Проект
  • На перевале: Сохранить проект и продолжить ...
  • Validate Задачи
    • На перевале: Сохранить задачи
    • при неудаче: Удалить проект (откат может быть?)

Так что мой вопрос сводится к следующему: Как я могу получить Rails для запуска метода project_id = (или project =) и проверки для детей (задач) ПОСЛЕ родительского (проект), но НЕ сохранить родительскую (проектную) модель, если какой-либо ребенок (задача) недействителен?

Любые идеи?

ответ

12

Используйте этот ответ для 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 
+0

Это не работает для меня. В validates_presence_of: project_id вызов «project» возвращает nil, заставляя его попробовать и проверить файл project_id и не выполнить проверки. Я задал еще один вопрос, потому что я думал, что проблема другая, но похоже, что она похожа на http://stackoverflow.com/questions/2102724/rails-nested-attributes-association-validation-failing. –

+10

Ниже приведено обратное решение для Rails 3.0 и выше. – nertzy

1

Вы можете просто создать проект и добавить только проекты, если она проходит проверку:

tasks = params.delete(:task_attributes) 
if Project.create(params) 
    Project.update_attributes(:task_attributes => tasks) 
end 

Ciao

0

Вопреки тому, что Bigo предполагает, что это не всегда приемлемо, чтобы сохранить родительский объект первым, а затем дети. Обычно вы хотите убедиться, что все объекты проверяются до их сохранения. Это дает пользователю возможность повторно редактировать форму ввода и исправлять любые ошибки.

Описанная вами проблема будет исправлена ​​в Rails 3.0. Я бы разместил ссылку на билет Lighthouse, но stackoverflow.com не разрешает это, потому что я новый пользователь (#fail). Но пока вы можете использовать плагин «parental_control», который исправит вашу «ошибку».

2

К сожалению, ни одно из приведенных выше предложений не работает для меня с Rails 2.3.5.

В моем случае проект в задаче всегда равен нулю, если оба они созданы с использованием вложенных атрибутов. Только если я удалю validates_presence_of, создание пройдет успешно. Единичный тест и журнал показывают, что все создано правильно.

Итак, теперь я бы хотел добавить ограничения к БД, а не к Rails, поскольку в первую очередь это кажется более надежным.

8

только проверить отношения, а не ID:

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 
+0

Наконец-то ответ, который я искал. – doug

159

Использование :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

Работал для меня на Rails 3.0 –

+1

Большое спасибо! Это прекрасно работало, и я не упоминал об этом нигде. – Emily

+0

undefined method 'validate_presence_of 'для Rails 3.2.3. Строка должна быть validates_presence_of: подземелье. – simeonwillbanks