Подтвердить что ты не робот

Rails: предотвращение создания родительской модели и появление ошибок проверки модели дочерней модели

Я некоторое время задерживался этой проблемой и полностью смутил себя тем, как совлокальные модели и проверки работают вместе.

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

#Image.rb
has_one     :content,
as:         :contentable,
inverse_of: :contentable,
dependent:  :destroy

#Video.rb
has_one     :content,
as:         :contentable,
inverse_of: :contentable,
dependent:  :destroy

#Content.rb
belongs_to   :contentable,
inverse_of:  :content,
polymorphic: true

validate     :all_good?

def all_good?
  errors.add(:base, "Nope!")
  return false
end

Любые выводы или идеи очень ценятся!

4b9b3361

Ответ 1

Rails имеет специальную проверку, называемую validates_associated, которая гарантирует, что соответствующая запись действительна. Если связанная запись недействительна, родительская запись также будет недействительной, и ошибка для ассоциации будет добавлена ​​в список ошибок.

В обоих классах изображений и видео добавьте следующее:

validates_associated :content

Теперь, если ассоциация content недействительна, видео или изображение не будут сохранены.

video = Video.new
video.content = Content.new
video.save #=> false
video.valid? #=> false
video.errors #=> [:content => "is invalid"]

Ответ 2

Короткий ответ

Добавить в фото и видео модель:

accepts_nested_attributes_for :content

Доказательство

Я был уверен, что знаю ответ на этот вопрос, но не был уверен, что он работал с полиморфными ассоциациями (которые я раньше не использовал), поэтому я установил небольшой тест.

Создал модели так же, как у вас есть ваша установка, но с атрибутом имени и с проверкой, которую я могу использовать для проверки отказа.

class Image < ActiveRecord::Base
  has_one     :content,
              as:         :contentable,
              inverse_of: :contentable,
              dependent:  :destroy

  validates_length_of :name, maximum: 10
end

class Content < ActiveRecord::Base
  belongs_to   :contentable,
               inverse_of:  :content,
               polymorphic: true

  validates_length_of :name, maximum: 10
end

Затем установите миграцию следующим образом:

class CreateImages < ActiveRecord::Migration
  def change
    create_table :images do |t|
      t.string :name

      t.timestamps null: false
    end
  end
end


class CreateContents < ActiveRecord::Migration
  def change
    create_table :contents do |t|
      t.string :name
      t.references :contentable, polymorphic: true, index: true

      t.timestamps null: false
    end
  end
end

Затем напишите RSpec, чтобы проверить, что родительский объект не сохранен, если дочерний элемент не может быть сохранен и что ошибки проверки будут пересчитаны.

  it 'should not save image if content is invalid' do
    image = Image.new()
    image.name = 'this is ok'
    expect(image).to be_valid

    content = Content.new()
    content.name = 'a string that should fail validation'
    image.content = content

    expect(image).to_not be_valid
    image.save

    expect(image).to_not be_persisted
    expect(content).to_not be_persisted

    expect(image.errors.count).to eq(1)
    expect(image.content.errors[:name][0]).to include('is too long')
  end

Выполнить тест и, конечно же, не получится.

Затем добавьте следующую строку в изображение (и видео)

  accepts_nested_attributes_for :content

Теперь проходят тесты - то есть, если ребенок не выполняет проверку, родитель также откажет проверку и не сохранит.

Ответ 3

Вам нужно повысить исключение в своей пользовательской проверке. сделать что-то вроде

before_save :ensure_all_good

def ensure_all_good
 try saving stuff to chile
 failed? raise nope
end