Rails / nested attributes / file_field doesn't show up within params when empty

1.6k views Asked by At

I'm having two models, the first one (model_1) accepts nested attributes for the second one (model_2). The second model has only one field (file), which is referenced in the form as file field.

The problem comes when no file has been selected. In this case — other than with say a text field — the field doesn't appear at all in the POST parameters which has the first model believe that no nested model should be created at all. Which fails to trigger validations etc.. If I were to add a second field to model_2 and the corresponding form and if I'm using a text input, everything will go through just fine and naturally validations work fine as well for the file field.

Anyone have experience on how to go about this?

And for better some (simplified) code — the form:

= 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

Model 1:

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

and Model 2:

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

There are 2 answers

4
Pan Thomakos On BEST ANSWER

I would suggest adding a check in your controller and returning a flash[:error] message if the file field is missing.

You could also manually add the fields if they don't exist, so that validation is triggered:

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

Finally, you could create a fake attribue in your model_2 Model that you could use to ensure the model_2_attributes get's passed in the form:

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
1
apneadiving On

At last, this seems to answer:

https://github.com/perfectline/validates_existence

Here is a sample:

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