3

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
polarblau
  • 17,649
  • 7
  • 63
  • 84
  • what if you create the model2 linked to model1 in your controller before creating the form? This way, the update for model2 couldn't ignore the validations no? – apneadiving Feb 05 '11 at 23:09
  • I am actually doing it this way `@model_2 = @model_1.model_2s.build`. Doesn't seem to change anything, though. – polarblau Feb 05 '11 at 23:28
  • You should add .save(false) to really save the object and bypass validation here – apneadiving Feb 05 '11 at 23:32
  • But wouldn't I end up with a lot of invalid entries like this? – polarblau Feb 05 '11 at 23:36
  • Yes, you're right, especially with your has_many relationship, it's a bad idea – apneadiving Feb 05 '11 at 23:41
  • 1
    Found this: http://stackoverflow.com/questions/3152001/validate-presence-of-nested-attributes But seems overkill compared to the hidden attribute – apneadiving Feb 05 '11 at 23:56
  • +1 This might be a solution after all (@Pan Thomakos is suggesting something very similar below) — I'm currently considering if this validation rule might be necessary in any case. There's still an open issue, though: What happens when I delete all of the children? The parent becomes invalid, right? But how to treat this case? Should the last child take the parent down as well? – polarblau Feb 06 '11 at 09:20

2 Answers2

1

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
Pan Thomakos
  • 34,082
  • 9
  • 88
  • 85
  • Thanks for your answer. I've been thinking about using a hidden input field as well, but all of these solutions somehow don't feel 100% `right` — it's all a little hacky, if you know what I mean? I'm still hoping to find a solution down Rails–way… – polarblau Feb 05 '11 at 23:31
  • 1
    You could also add a validation to Model1 to make sure that it has at least one Model2 related to it - that would cause another validation failure if Model2 was not present. – Pan Thomakos Feb 06 '11 at 00:05
  • +1 This seems like the best solution so far. I'll think about this a little further and get back. – polarblau Feb 06 '11 at 09:20
  • I've added a `hidden_field :force_validation` and added an accessor to the model. This works (hence answer accepted), but still bothers me. Maybe I'll find a better solution in a re–factoring round. Validation is still an open suggestion which just currently doesn't fit into my design. Cheers! – polarblau Feb 07 '11 at 19:51
0

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
apneadiving
  • 114,565
  • 26
  • 219
  • 213
  • Thanks, looks interesting. But this won't work for the `has_many` side of the relationship, how I see it? This type of validation has been discussed a few times (see apneadiving's comment or http://stackoverflow.com/questions/4309354/rails-nested-attributes-require-at-least-two-records) but I'm currently still struggling with the simple limitation that comes with the file field not showing up at all rather than empty (like a checkbox, if you will) in this particular case as well as some design choices I've made. I'll get back. – polarblau Feb 07 '11 at 07:56