form_remote_tag

Try putting your result in an entirely different div, this way you
won't need to write any logic.

Darren Evans wrote:

Thanks for the reply. That doesn't work though (I changed it to form_new
to test), maybe I am doing something stupid?

One code review coming up.

Darren

View:
<div id="form_new">
  <table border="1" cellpadding="0" cellspacing ="0">
     <tr>
       <td>
       <%= form_remote_tag :update => "form_new", :url => {:action =>
"form" }, :complete => evaluate_remote_response%>

I never use :update any more. I always use RJS in the action to point
to the specific variables that need an update.

Further, I think that updating the entire DIV containing a FORM is bad
luck. Of course it will work, but I would rather the browser can
preserve the original FORM's context, at least so the user doesn't
lose their focus and selection at submit time.

You are allow to update things other than DIVs, you know!

         <select id="form1" name="form1"
onchange="this.form.onsubmit();">
            <%= options_from_collection_for_select @counties, "id",
"county_name", @county_id.to_i%>
         </select>

That will submit the FORM each time the user changes a value. This is
bad usability, and it would repaint the FORM, destroying the user's
context before they can select the value they actually want. Submit
buttons are sometimes good things; they help the user decide and then
commit in two steps.

          <%if !(@districts.empty?)%>
           <br>
          <select id="form2" name="form2"
onchange="this.form.onsubmit(); return false;">
            <%= options_from_collection_for_select @districts, "id",
"district_name", @district_id.to_i%>
         </select>
         <%end%>

         <%if (@institutions)%>
           <%for institution in @institutions%>
               <%institution.name%>

That has to mean <%= institution.name %>, right?

           <%end%>

I had forgotten Ruby supports a for command. You should practice using
@institutions.each do, because it provides tighter scope, and leads to
more elaborate iterations, such as .insert, .reject, .map(&:name),
etc.

           <br>

I always write XHTML. <br/>. And my test cases use assert_xpath which
demand XHTML (for short segments of the HTML.)

You do _have_ test cases, don't you?

            <select id="form3" name="form3"
onchange="this.form.onsubmit(); return false;">
               <%= options_from_collection_for_select @institutions,
"id", "name", @institution_id.to_i%>
            </select>
        <%end%>
        <%= submit_tag "Go" %>

Why you have submit tags built into the select items, _and_ a submit
button? Those onchange handlers might not do what you think.

        <%= end_form_tag %>

That thing is deprecated. I suspect one should use </form>. That leads
to the lamentable situation where a <%%> starts a block and a </> ends
it, but I suspect the form_ tags also take do...end blocks, so <% end
%> might work there if you put a do up top.

    </td>
</tr>
</table>
</div>

Controller:

This action is way too long. You should write tests for all of it, and
then refactor it to pull all the model-specific stuff out to the
model, or to helpers. For example...

def form
@counties=Countyname.find(:all, :order =>"county_name",
:conditions=>["language_id = ?", session[:language_id]])

That could be @counties = county_list(), where a helper hides the ugly
stuff and gives it a useful name.

if (params[:username])
session[:user_suggested]=(params[:username])
session[:password_suggested]=(params[:password])

redirect_to(:controller => 'login', :action => 'login')
return
end

You have several little actions here masquerading as one big action.
Split them up into multiple actions, give each one a name and a guard
clause enforcing how the browser must call it, and make each action as
short and sweet as possible.

The guard clause for that username action could be

   return if request.xhr?

for example, to prevent Ajax from calling it (if that's what you mean).

And the Joy of Ruby is how close you can get these expressions to
normal English. Enforce that wherever you can, including in your
variable name selections. Upgrade username to user_name.

if request.post?

Again, this is another action hiding inside this one. its guard clause
would be return unless request.post?

   @county_id=Countyname.find(:first, :conditions => ["county_id = ?",
params[:form1].to_i]).id
end

@districts=District.find(:all, :order => "district_name",
:conditions=>["county_id = ?", @county_id])
if request.post?
   @dist=District.find(:first, :conditions => ["id = ? and county_id =
?", params[:form2].to_i, @county_id])
   if (@dist)
     @district_id =@dist.id
   else
     @district_id=District.find(:first, :conditions => ["county_id =
?", @county_id]).id
   end
end

I don't think every single one of your variables needs a @.

if (params[:form1] && params[:form2])
   @places=Place.find(:all, :order => "institution_id", :conditions =>
["district_id = ?", @district_id])
   @institutions=[]
   @institution_display=1
   for place in @places
     @res=Institution.find(:first, :conditions=>["id = ?", place.id])
     @institutions << @res
     if request.post?
       @institution_id=params[:form3]
     end
   end

I suspect this would work, off the top of my head:

  institutions = Institution.find(places.map(&:id))

There is some variation on find() that takes an array of ids, so don't
call find() in a loop if you can just pass that array in.

   if !(@institution_id.nil?) && (@district_id && @county_id &&
!@institution_id.empty?)
   session[:institution_id]=@institution_id
   session[:district_id]=@district_id
   session[:county_id]=@county_id
   session[:institution_name]=Institution.find(:first, :conditions =>
[“id= ?”, session[:institution_id]]).name
   session[:district_name]=District.find(:first, :conditions => [“id=
?”, session[:district_id]]).district_name
   session[:county_name]=Countyname.find(:first, :conditions => [“id=
?”, session[:county_id]]).county_name
   #render(:text => “<script>window.location.href =
http://localhost:3000/login/register’</script>”)

I never use the session object, and you have a "latent model" here.
You should pull all those variables out of the session and put them
into a model, with a good name that reveals its intent.

   render :update do |page|
   page.redirect_to(:controller => 'login', :action => 'register')
end

render :update is incompatible with the :update option in the form_remote_tag.

Next, you are redirecting to paint a complete page, with its layout
and everything. Rails doesn't care that you are pushing the result
into a DIV in another page!

   end
end
end

Try moving all the DIV's contents into a partial, with a name better
than _form.rhtml, and then <% render :partial => 'form' %> inside the
calling RHTML.

Then leave in the :update tag, for now, and replace this render with
render :partial => 'form'

After that works, look up the system to pass variables into a partial,
so you can take out lots of session and @.

The reason we all like Rails here is we have experience with Brand X,
where all forms and actions are completely crammed with sickeningly
irrelevant details. Rails leads us to write forms and actions that
really do look like the ones in the Agile Web Development with Rails
books - very short, completely readable, with almost no administrivia
and paperwork just to get something done. You should spend a little
time learning more Ruby, and then seeing how small you can make all
this code, before adding more features to it.