Stumped by Ajax + Session + Saving Model + Private Method

Got stumped by this one… Had a working form_remote_tag that used
rjs to toggle between a static view of the data and a form with
inputs. Saving that form updated an ActiveRecord model.

Then I realized I needed to move the actions I was using to view/edit/
save this form into the private section of the controller (calling
them directly via URL not a good thing).

Now the Saving doesn’t actually save anything. No crashes, but the
data isn’t updated. I suspect it is because I store the ID of the
object in a session, and somehow the Ajax invocation of the action
fails to restore the session – but why the method being private vs
public would matter to that, I don’t know. Or maybe it is something
else.

The saving method looks like this:

def emergency_contact_save

 @client = Client.find(session[:selected_client_id])
 @client.emergFirstName = params[:emergFirstName]
 ..... more params .....
 @client.save
 respond_to do |request_format|
   request_format.js
 end

end

works perfect if it is a public method, doesn’t work if it is private.

Not sure what other code I’d need to show.

Any ideas??

– gw

If emergency_contact_save is the method you are calling from your form
and you moved it from public to private you should know then you
cannot call a private method via a request. Or is
emergency_contact_save called from def save which is public?

Cheers,
Nicholas

Yeah I was just about to post that after thinking about this, I
realized the Ajax request is still making a call to a public URL that
Rails is going to map to an action. The screen gymnastics continued
to work because Rails would still find the .rjs file and run them.

OK, so here’s the real problem – if I put it all back as public
actions, then using the web UI works all good. However, if I simply
enter a URL for that Ajax into the browser I get a big messy
javascript upchuck on the page, and it wipes out the data in that
model that is supposed to be updated because there is no data.
Clearly, calling this URL directly is not good.

Submitting no data (i.e. clearing what existed) is a valid
submission, so I can’t just add some code that says an submission
with all fields as empty is invalid – it’s not invalid.

So, what’s the pattern for ensuring that calls to controller actions
are called by their proper Ajax context? That and I have to figure
out why the Javascript upchuck?

– gw

I think it’s your implementation of the form/params hash that could
improve and solve your issue here:

— controller —

def emergency_contact_save
@client = Client.find(session[:selected_client_id])
@client.attributes = params[:client] # instead of setting them
individually
@client.save
respond_to do |request_format|
request_format.js
end
end

— view —

<% remote_form_for @client do %>
…fields…
<%end %>

This way if the params[:client] has is nil none of the attributes will
be touched.

HTH,
Nicholas

On May 12, 2008, at 8:24 PM, Nicholas H. wrote:

I think it’s your implementation of the form/params hash that could
improve and solve your issue here:

Nah, that doesn’t matter. How the model is poulated isn’t relevant.
I’ve removed the model altogther to better understand what Ajax and
Rails are doing here, and somehow, Rails is still trying to call the
RJS template even when the request is not XHR.

So, I now have this:

def emergency_contact_save

 if request.xhr?
   .... logger step comfirms an XHR request ....

   respond_to do |request_format|
     request_format.js
   end
 else
   .... logger step comfirms a Non-XHR request ....
 end

end

And, I have a file emergency_contact_save.rjs

All works fine when using the web UI.

When I use a direct URL /{controller}/emergency_contact_save I still
get a javascript error which seems to come from Rails trying to run
the emergency_contact_save.rjs file.

If I remove the emergency_contact_save.rjs file and again try the
URL /{controller}/emergency_contact_save I get a Rails error saying
there is no rjs file.

Now, that makes no sense to me at all that Rails should still be
trying to find the rjs file at this point.

Since that testing, I’ve restarted Rails and that seems to have
changed a few things. Then I ended up building up to this code (added
redirect):

def emergency_contact_save

 if request.xhr?
   .... logger step comfirms an XHR request ....

   respond_to do |request_format|
     request_format.js
   end
 else
   .... logger step comfirms a Non-XHR request ....

   redirect_to :action => '...the basic view of the page...'
 end

end

That combination of xhr? and the redirect seems to be the cure. Now,
maybe I need to do some refactoring to allow a legit POST, but for
now this seems to take care of the problem of how to handle Ajax vs
non-Ajax calls.

Thanks for bouncing some ideas, Nicholas.

– gw

You could also do something like this at the top of your controller:

verify :only => ‘emergency_contact_save’, :xhr => true.

That would be nicer than having the conditional statement in the
method

Nicholas

Greg:

In addition, I think the catch all route at the end of your routes
file will ignore the format and pickup the default template in this
order:

emergency_contact_save.html.erb
emergency_contact_save.rjs.js

The respond to stuff would only work strictly if you were using routes
defined by resources and you had no catch all route at the end. I
might be totally wrong here, but worth a try if you are interested.

HTH,
Nicholas

OK, I’ll check that stuff out – thanks.

– gw

On May 12, 2008, at 9:12 PM, Nicholas H. wrote:

The respond to stuff would only work strictly if you were using routes

improve and solve your issue here:
if request.xhr?

there is no rjs file.

 end

– gw


def gw
acts_as_n00b
writes_at ‘www.railsdev.ws’
end

Just to clarify, that should be

emergency_contact_save.js.rjs

..

action = ‘emergency_contact_save’
format = ‘js’ (as in, respond_to do |format| … format.js… )
renderer = rjs engine (vs erb/haml/builder/etc)

On May 12, 2008, at 9:07 PM, Nicholas H. wrote:

You could also do something like this at the top of your controller:

verify :only => ‘emergency_contact_save’, :xhr => true.

That would be nicer than having the conditional statement in the
method

Ah, ok, verify does the exact same thing as the conditional.
Interesting. Now, whether it’s “nicer” is questionable IMO.

In a case where the same conditions and actions apply to multiple
actions, I can see the attraction of eliminating the redundancy, but
in cases where it’d be the rare method that uses the verify, IMO
having the conditional right in the method code is more explicit, and
not prone to missing those details. I’m not a fan of splitting up
code like this (again, unless it is something where the redundancy
would become tedious, then splitting the code with verify becomes the
lesser “evil”).

Anyway, I can see that using Ajax requires more planning than just
banging out the css and rjs files, and there’s a few options to deal
with it.

Thanks for your help.

– gw

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs