Redirecting back on errors to multi-form pages

I am struggling with error handling on forms when the data entered wont
validate.

The trick of using render instead of redirect doesn’t seem to work
because my collection selects on the other forms on the page need
instance variables?

How do I get the invalid params and error messages sent back to a multi
form page?

Also, is there some method like a ~ “test_save” that I could use to test
if given set of parameters would save and use that method for
conditional logic (preferably with would be error messages created).

On page 493 of AWDWR I see this use of “.valid?” . Can I use that and
shuttle back the params in an object to the redirect_to method in the
else clause if it would fail?

Tom, can you post your controller code, it will probably be best to
show you by example.

On Nov 19, 12:43 am, Tom N. [email protected]

Nicholas H. wrote:

Tom, can you post your controller code, it will probably be best to
show you by example.

On Nov 19, 12:43 am, Tom N. [email protected]

Thanks for the offer to help. Hope its not too lengthy.

Here is the controller action that calls the page with the initial form.
Below are the controller actions that get called from different forms on
formations_fpositions.rhtml and hopefully will redirect (or render) back
to the initial form with validation errors and partially completed param
data.

def formations_fpositions
#for select box to navigate what parent to work under in left column
@coach_formations = []
@coach_formations = @coach.formations
@formation = session[:formation]

to set up form for new fpostion object (or hopefully get the one with

errors back)

in two form boxes center collumn

@fposition = Fposition.new(params[:fposition]) #if new object

this holdes info if the page is called by selecting an existing

fposition
@fposition_to_edit =
Fposition.find_by_id(session[:fposition_to_edit]) if
session[:fposition_to_edit]
if @formation #forces a user to select a formation before
making fpositions
if @coach_formations[0]
session[:formation] = @coach_formations[0]
#these set up association select boxes in right column
@formation = session[:formation]
@formation_fpositions = @formation.fpositions || []
@coach_fpositions = @coach.fpositions || []
else
redirect_to :action => ‘create_formation’
end
else
#these set up association select boxes in right column for other prong
of fork
@formation_fpositions = @formation.fpositions || []
@coach_fpositions = @coach.fpositions || []
@fposition_hash = create_fposition_hash
end
end

#1 here is the controller action to save info put in the new fposition
form.

def create_fposition
@fposition = Fposition.new(params[:fposition])
@formation = session[:formation]
@coach = session[:coach]
#need help here
if @fposition #! Help here please…need a condition !!!
@formation.fpositions << @fposition
@coach.fpositions << @fposition
@coach.save
session[:formation] = @formation
session[:coach] = @coach
@fposition = Fposition.new
redirect_to :action => ‘formations_fpositions’
else
#! Help here please ! If I use the render below I get errors
#based on nil object in select box
render :action => ‘formations_fpositions’
end
end

#2 I have almost the same issues with the controller action to save
changes entered on the edit fposition form

def update_fposition
fposition = Fposition.find(params[:id])

  if fposition.update_attributes(params[:fposition_to_edit])
     session[:fposition_to_edit] = nil
    redirect_to :action => 'formations_fpositions'
  else

#render doesn’t work and not sure about error conditions with
update_attributes
#if i “redirect_to” the page after an error, I end up creating a new
object.
#how can I grab the present params, the would be error messages and send
them
#perhaps to the “edit” form instead of the new form?
render :action => ‘formations_fpositions’
end
end

The user really needs to see the context they are working in and see
their partial work as they continue to enter data for additional
objects…thats why there are three columns showing which parent they
are under and display of “siblings”.

Thanks in advance for taking the time to try to see what I’m not
getting.

Ok here’s a try with the pastie… hope the help offer still stands
Nicholas (hope you enjoyed your turkey too1)… I really appreciate any
help.

Again, my problem is finding away to return the user to the multi-form
page with the the partial data and error messages displayed in the
section of the page they were working on. As it stands the validation
works but fails silently for a new position without required location
attribute(as an example).

I am not really sure why you needed the coach model but its included. It
is just selected from a list in another view and stored in session (and
retrieved by almost all action as a before filter).

The validations are working with the fposition model but fail silently.
When I try to use render :action instead of redirect_to :action I get
errors because the render seems to have forgotten all the instance
variables… I tried a before filter but that doesn’t seem to trigger on
a render :action either.

http://pastie.caboo.se/122244

Tom,

Can you please paste the entire controller so I can see how things
like @coach are getting populated. And also post the Coach model (I’m
assuming there is one). Please use http://pastie.caboo.se/ so I don’t
have to reformat the code (after getting mangled) :slight_smile:

http://pastie.caboo.se/

Cheers,
Nicholas

On Nov 19, 1:40 pm, Tom N. [email protected]

Hey, no problem, Tom - I thought I had provided a solution before :slight_smile:

Honestly, I wouldn’t worry about the performance at this point. I’m
not sure what sort of traffic you are expecting, but if it does become
a problem you could try implementing a caching mechanism (e.g.
memcache) if it does become an issue. For now, go with the before
filters and it will save you a lot of headaches.

I must say though, I would really recommend splitting that controller
up though. It looks like you are maintaining about 5 different
resources/models in the one controller. It would make it a lot easier
for you to split them out into five different controllers - each for
coach, teams, players etc. I think it would make things a lot easier
to maintain.

Is that enough to move you forward?

On Nov 26, 9:35 pm, Tom N. [email protected]

Darn I’m dumb.

I just figured out that you suggested (in another thread here
http://www.ruby-forum.com/topic/132210#new ) using the before filter
Before (!) the save/update action, for the possibility that it might
fail and hence be prepared for the new render. I kept thinking we
needed something that would only get called it the validation failed.

Seems like extra processor time preparing for errors that might not be
made but I guess that sort of calculation is minuscule.

I really have no clue what sorts of “queries” , checks of variable
values, calculations, etc might be issues for cost/efficiency of a web
ap and which are not.

Are there any rules of thumb? (is something like find_by_id(:id) way
slower than Model1.model2s ?

Nicholas H. wrote:

Is that enough to move you forward?

inch by inch, step by step … thanks yes.

I must say though, I would really recommend splitting that controller
up though. It looks like you are maintaining about 5 different
resources/models in the one controller.

Yes, and I was planning on adding a few more too.

My thinking is that because the views are generally shared between a
couple models, that I should put the actions to update the various
models and associations in one controller that calls the interrelated
views ?

It is cumbersome in its length but moving the views outward to other
controllers would lead to error’s related their address and perhaps more
duplication in permissions etc eventually. Having all the crud stuff
for so many models all in one place doesn’t seem quite right though,
except that it feels more simple and less arbitrary…related views
belong together? but do actions belong near the views and where do they
go when the action modifies two or three models?

Tom,

Even though your “composite” view displays different models you can
split it into different controllers. Let’s use a basic example of a
team has_many players. For this example, I would have two controllers,
TeamsController and PlayersController. This would allow for individual
updates of each of the models. Even though my “show” method for a team
has a list of players as well. In my show template, I can all players
in that team by doing something like this:

Team Detail View

<%= @team.name %>

<%= render :partial => “players/player”, :collection => @team.players
%>

In this example I am listing all players of a team with a partial in a
different directory. This naming convention is nice way to go because
in rails 2.0 you will be able to do this:

<%= render :partial => @team.players %>

Finally, if you have the situation that you create a player when you
create a team you could do something like this in your
TeamsController:

def create
@team = Team.new(params[:team])
@player = @team.players.build(params[:player])
if @team.save
redirect team_url(@team) # or simpley redirect @team in rails 2.0
else
render :action => ‘new’
end
end

if you were simply adding a player to an existing team do this in your
PlayersController:

def create
@team = Team.find(params[:team_id])
@player = @team.players.build(params[:player])
if @player.save
redirect team_url(@team) # or simpley redirect @team in rails 2.0
else
render :action => ‘new’
end
end

If you want a complete example check out Beast (forum written rails)
to show you how to divide an application up.

http://svn.techno-weenie.net/projects/beast/trunk/

You may consider doing a little reading on RESTful design. Although
you may not want to make it a restful application, it’s a great design
technique. Basically, there is a one to one mapping of controller to
model and you controller is restricted to the following methods:
index, show, new, create, edit, update, and destroy. There’s always
exceptions of course, but its a great pattern to following.

Helpful? Confusing? :slight_smile:

Cheers,
Nicholas

On Nov 27, 4:56 pm, Tom N. [email protected]