Problems with multiple ActiveRecords and Validations

Hi all,

I am a RoR newbie and have the following scenario set up:

There are 2 ActiveRecords involved, the first one being “User”, the
second one being “Visibility”.

The corresponding users table holds address informations regarding a
User. The visibilities table holds visibility settings for the
individual columns of the users table (i.e. firstname, lastname, country
should be visible to everybody while the credit card data should be only
visible to the admin, and so on) for individual users. It has
practically the same schema as the users table and a foreign key, namely
user_id. The relationship between the tables is 1:1.

Now I have created an “edit user profile” view which displays all the
individual form elements corresponding to the columns of the user table.
Next to each form element is a checkbox which is populated from the
visibilities-table. (Un-)checking the checkbox you can decide which
elements should be visible in the “show user profile” view. I hope you
can follow me so far.

Everything is handled from a UserController which extracts the
visibility alongside the user and prepares everything for display.

Problems arise, if the ActiveRecord validations come into play (e.g.
there is a validates_presence_of :lastname rule). If everything
validates successfully, the update action is invoked and all changes are
saved (in the users and visibilities tables). But if a validation fails
and the edit user profile view is rendered once again ONLY the submitted
values of the User ActiveRecord are filled into the form fields once
again. But all the checkboxes are unchecked!

I haven’t been able to figure out what exactly does happen in case a
validation fails, although I have screened the source code of the
ActiveRecord and ActiveView classes and come across the magic errors
object.

Here some source code:

users_controller.rb:

def edit
@user = User.find(params[:id])
@visibility = @user.visibility
end

user.rb
class User < ActiveRecord::Base
validates_presence_of :lastname, :firstname
has_one :visibility
end

edit.rhtml (excerpt)
<%= text_field ‘user’, ‘lastname’ %>
<%= check_box ‘visibility’, ‘lastname’, {}, “public”, “admin” %>

I am desperately trying to make that work. Any ideas?

Best regards,
Dominik

Dominik wrote:

users_controller.rb:

def edit
@user = User.find(params[:id])
@visibility = @user.visibility
end

user.rb
class User < ActiveRecord::Base
validates_presence_of :lastname, :firstname
has_one :visibility
end

edit.rhtml (excerpt)
<%= text_field ‘user’, ‘lastname’ %>
<%= check_box ‘visibility’, ‘lastname’, {}, “public”, “admin” %>

I am desperately trying to make that work. Any ideas?

Best regards,
Dominik

You might want to post your “update” action from users_controller, too.
It’s hard to tell what happens exactly without that.

Jeff C.man

Hi all,

I just wanted to tell you how delighted I am now: I have found the bug
after one night’s sleep - stupid me!

It had nothing to do with the edit or update action (which I posted
above) but with the new/create actions: the line @visibility =
@user.visibility was missing and consequently the new action could not
fill in the checkboxes after a failed update from the instance variable
@visibility.

For all the newbies in the world I just want to explicitly state that
the validations take place while update_attributes is running. If any
validations fail update_attributes returns false and you can control
what happens next with a call to render :action or redirect to :action.

Rails rocks!

Jeff C.man wrote:

Dominik wrote:

users_controller.rb:

def edit
@user = User.find(params[:id])
@visibility = @user.visibility
end

user.rb
class User < ActiveRecord::Base
validates_presence_of :lastname, :firstname
has_one :visibility
end

edit.rhtml (excerpt)
<%= text_field ‘user’, ‘lastname’ %>
<%= check_box ‘visibility’, ‘lastname’, {}, “public”, “admin” %>

You might want to post your “update” action from users_controller, too.
It’s hard to tell what happens exactly without that.

Here you are:

def update
@user = User.find(params[:id])
@user.create_visibility(params[:visibility]) unless @user.visibility
@visibility = @user.visibility
if @user.update_attributes(params[:user]) &&
@user.visibility.update_attributes(params[:visibility]) then
flash[:notice] = ‘Update was successful.’
redirect_to :action => ‘show’, :id => @user
else
render :action => ‘edit’
end
end

And here is the relevant form-tag from the view, but that is quite
obvious:
<%= start_form_tag :action => ‘update’, :id => @user %>

Thanks in advance!

Dominik