Rails/вложенные атрибуты/file_field не отображаются в параметрах, когда они пусты

У меня есть две модели, первая (model_1) принимает вложенные атрибуты для второй (model_2). Вторая модель имеет только одно поле (file), которое упоминается в форме как поле файла.

Проблема возникает, когда файл не выбран. В этом случае — за исключением, скажем, текстового поля — поле вообще не отображается в параметрах POST, в которых первая модель считает, что вложенная модель вообще не должна создаваться. Который не запускает проверки и т. д. Если бы я добавил второе поле в model_2 и соответствующую форму, и если я использую текстовый ввод, все пройдет нормально, и, естественно, проверки также будут работать нормально для поля файла.

У кого-нибудь есть опыт, как это сделать?

А для лучшего (упрощенного) кода — вид:

= form_for @model_1, :html => { :multipart => true } do |f|
    - # fields for model 1 …
    = f.fields_for :model_2 do |builder|
        - # if this is empty, it's like no model_2 would be created at all:
        = builder.file_field :file

Модель 1:

class Model1 < ActiveRecord::Base
    has_many :model_2s, :dependent => :destroy
    accepts_nested_attributes_for :model_2s
    # …
end

и Модель 2:

class Model2 < ActiveRecord::Base
    belongs_to :model_1
    validates_presence:of :file
    # …
end

person polarblau    schedule 05.02.2011    source источник
comment
что, если вы создадите модель2, связанную с моделью1 в вашем контроллере, прежде чем создавать форму? Таким образом, обновление для модели 2 не могло игнорировать проверки, нет?   -  person apneadiving    schedule 06.02.2011
comment
Я на самом деле делаю это так @model_2 = @model_1.model_2s.build. Хотя вроде ничего не меняет.   -  person polarblau    schedule 06.02.2011
comment
Вы должны добавить .save(false), чтобы действительно сохранить объект и обойти проверку здесь   -  person apneadiving    schedule 06.02.2011
comment
Но разве я не получил бы много недействительных записей, подобных этой?   -  person polarblau    schedule 06.02.2011
comment
Да, вы правы, особенно с вашими отношениями has_many, это плохая идея.   -  person apneadiving    schedule 06.02.2011
comment
Нашел это: stackoverflow.com/questions/3152001/ Но кажется излишним по сравнению со скрытым атрибутом   -  person apneadiving    schedule 06.02.2011
comment
+1 В конце концов, это может быть решением (@Pan Thomakos предлагает что-то очень похожее ниже) — сейчас я думаю, может ли это правило проверки быть необходимым в любом случае. Однако остается открытым вопрос: что произойдет, если я удалю всех дочерних элементов? Родитель становится недействительным, верно? Но как лечить этот случай? Должен ли последний ребенок забрать и родителя?   -  person polarblau    schedule 06.02.2011


Ответы (2)


Я бы предложил добавить проверку в вашем контроллере и вернуть сообщение flash[:error], если поле файла отсутствует.

Вы также можете вручную добавить поля, если они не существуют, чтобы активировать проверку:

m1params = params[:model_1]
m1params[:model_2_attributes] = {} unless m1params.has_key?(:model_2_attributes)

Наконец, вы можете создать поддельный атрибут в своей модели model_2, который вы могли бы использовать для обеспечения того, чтобы атрибуты model_2_attributes передавались в форме:

class Model2
  attr_writer :fake

  def fake
    @fake ||= 'default'
  end
end

= form_for @model_1, :html => { :multipart => true } do |f|
    - # fields for model 1 …
    = f.fields_for :model_2 do |builder|
        = builder.hidden_field :fake
        = builder.file_field :file
person Pan Thomakos    schedule 05.02.2011
comment
Спасибо за Ваш ответ. Я тоже думал об использовании скрытого поля ввода, но все эти решения как-то не кажутся 100% right — это все немного хакерски, если вы понимаете, о чем я? Я все еще надеюсь найти решение на Rails-way… - person polarblau; 06.02.2011
comment
Вы также можете добавить проверку к Model1, чтобы убедиться, что с ней связана хотя бы одна Model2 — это приведет к еще одному сбою проверки, если Model2 не будет присутствовать. - person Pan Thomakos; 06.02.2011
comment
+1 Пока это кажется лучшим решением. Я еще немного подумаю об этом и вернусь. - person polarblau; 06.02.2011
comment
Я добавил hidden_field :force_validation и добавил к модели метод доступа. Это работает (поэтому ответ принят), но меня все еще беспокоит. Может быть, я найду лучшее решение в раунде рефакторинга. Валидация все еще остается открытым предложением, которое в настоящее время не вписывается в мой дизайн. Ваше здоровье! - person polarblau; 07.02.2011

Наконец, это, кажется, отвечает:

https://github.com/perfectline/validates_existence

Вот пример:

class Unicorn < ActiveRecord::Base
  belongs_to :wizard
  belongs_to :person, :polymorphic => true

  validates :wizard,    :existence => true
  validates :wizard_id, :existence => true # works both way
  validates :person,    :existence => { :allow_nil => true, :both => false }
end
person apneadiving    schedule 06.02.2011
comment
Спасибо, выглядит интересно. Но это не сработает для has_many стороны отношений, как я это понимаю? Этот тип проверки обсуждался несколько раз (см. комментарий apneadiving или stackoverflow.com/questions/4309354/), но в настоящее время я все еще борюсь с простым ограничением, которое связано с тем, что поле файла вообще не отображается, а не пусто ( как флажок, если хотите) в этом конкретном случае, а также некоторые варианты дизайна, которые я сделал. Я вернусь. - person polarblau; 07.02.2011