Pascal Luxain
Pascal Luxain

Reputation: 281

Rails3 association and accepts_nested_attributes_for failing when validation of user_id on

I am following the Rails Tutorial doing a little project for myself and then try to progress.

Well I am facing a problem for which I found the solution, but I'll really appreciate any thoughts and opinions because to make it work I have to disable a validation in an association.

The context is as follow : the application (big name for what it does actually...) has users to track their weight. I would like that when a user sign up, he/she enters a first measure on the go.

So here are the simplified models:

User.rb

class User < ActiveRecord::Base
  attr_accessible :email, :name, :password, :password_confirmation, :measures_attributes

  has_secure_password

  has_many :measures, dependent: :destroy
  accepts_nested_attributes_for :measures

  # here goes validations before_save, etc. taken from the Rails Tutorial
end

Measure.rb

class Measure < ActiveRecord::Base
  attr_accessible :weight
  belongs_to :user

  # This is kind where the problem is...
  # If I deactivate the validation for user_id everyhing goes fine
  validates :user_id, presence: true
  validates :weight, presence: true, numericality: { greater_than: 0 }

  default_scope order: 'measures.created_at ASC'
end

Here is the Users controller

class UsersController < ApplicationController

  # GET /users/new
  def new
    @user = User.new
    @user.measures.build
  end

  # POST /users
  def create

    @user = User.new(params[:user])

    if @user.save
      sign_in @user
      flash[:success] = "Hi #{@user.name}. Welcome !"
      redirect_to @user
    else
      render :new
    end
  end

end

Here is the form partial for the user :

<%= form_for(user) do |user_form| %>
  <%= render 'shared/error_messages', object: user_form.object %>

  <%= render 'users/fields', user_builder: user_form %>

  <%= user_form.fields_for :measures do |measure_fields| %>
    <%= render 'measures/fields', measure_builder: measure_fields, full: true %>
  <% end %>

  <%= user_form.submit submit_text, class: 'btn btn-large btn-primary' %>
<% end %>

And even when I fill the form correctly, I get this error :

* Measures user can't be blank

The only way I found to make it work is to get rid of the :user_id validation for presence in the Measure model. I want to emphasize that when this validation is off, the user is saved, the measure is saved and correctly associated with the newly created user.

Am I doing something wrong ? Is the :user_id presence validation in the Measure model really useful (it is in the Rails Tutorial and it makes perfectly sense for me) ? If yes why is the Measure validation failing when it is on ?

Thanks a lot in advance.

Upvotes: 0

Views: 371

Answers (2)

John H
John H

Reputation: 2488

You could try validates :user instead of user_id. Then it might work out that the two are associated in memory even though the User hasn't been saved yet.

Upvotes: 1

Geoff
Geoff

Reputation: 2228

I think I may have found an error in your code that would cause the error you're seeing.

In your new controller you specifically create an association:

@user.measures.build

In your create controller, you create a new element based on the fields that were passed in.

@user = User.new(params[:user])

There are some cases where the associated element will be dropped. I can't remember if this happens by default if it doesn't validate or if there was an option you need to set to make it drop.

I think you may need to add

@user.measure.build if @user.measures.empty?

in your create controller else clause before render :new.

I don't know if you're actually hitting this problem, but it would explain why the association to your User wasn't set.

Upvotes: 0

Related Questions