views:

185

answers:

2

This is possibly a newbie question, but I'm not sure what terms to search for.

Say I have a CUSTOMER object, and I want to send a MESSAGE to that customer.

What I would do first is add a SENDMESSAGE action on the CUSTOMER controller, which builds the message object. (Assume this is the right thing to do?)

In this instance however, rather than actually send the message from within this action, I need to forward to the edit view of the MESSAGE to capture the body text etc.

The question: I want to do this without persisting the object. I want to build the object here and then hand it over to another view for completion.

def sendmessage
    @message = Message.new
    @message.title = 'WIBBLE'
    @message.thecustomer = self
    @message.save    
    respond_to do |format|
      format.html { redirect_to(edit_message_path(@ message)) }
      format.xml  { render :xml => @ message }
    end
end

Maybe my question boils down to, what is the 'rails way' to cache parameters and objects across requests and multiple screens.

Happy to be pointed towards Web URLs as I expect this is simple.

Thanks

+1  A: 

The standard way to persist data across requests when building Web applications is to use the HTTP session. Rails makes an implicit session hash available for this purpose. It's used like this:

session[:message] = @message #store
@message = session[:message] #retrieve

You can also use the Rails flash session wrapper for passing information from the current action to the next. It's usually used for storing text to be displayed in the UI, but you can use it for persisting any object:

flash[:message] = @message #store
@message = flash[:message] #retrieve

In both cases, the objects that you're storing must be serializable. Note that by default Rails stores session data in an encrypted cookie on the client; consider it a strong hint that storing a lot of data in the session is frowned upon in the Rails world.

John Topley
Many thanks John. Session content in a cookie sounds like an odd design decision!
Can I also ask, would you use the session to cache across controller actions. e.g. my INDEX action performs a funky query based on incoming parameters. I want to cache that specific result list for the subsequent call to SENDMESSAGE. (This could potentially mean thousands of objects stored in the session cookie so guessing no.) However, at the time of calling SENDMESSAGE, I do not have all of the parameters needed to rebuild the CUSTOMER list again? Maybe cache these parameters? (Lots of ways to do this but looking for the rails way!
It sounds like caching the parameters so you can reconstruct the query would be the way to go. Note that I said that the cookie session store is the Rails default. The `config.action_controller.session_store` option in `environment.rb` lets you use the database for session storage instead.
John Topley
Don't store the actual objects: store IDs instead. That makes the session much smaller.
François Beausoleil
A: 

The is actually a pretty common task that you're over complicating. The Rails way to handle this is not to persist the object in question, but instead just render the view that will complete the action.

class CustomersController < Application Controller
  def sendmessage
    @message = Message.new
    @message.title = 'WIBBLE'
    @message.thecustomer = self
    respond_to do |format|
      format.html { render "messages/edit" }
      format.xml  { render :xml => @ message }
    end
  end
end

In general persisting whole objects across HTTP requests in Rails is a bad idea, the only real way to do it is to is to through the session or flash hash as John Topley suggests, but both of those are limited in the amount of space available. Which is why François Beausoleil suggests to only store the object id in the session. Either way you should clear either hash when you're done with it.

What you should be doing here, is designing your controller actions such that each action fully completes a task. Completing half a task and redirecting so a second action can complete the task may be slightly more DRY, but, it doesn't gel well with the Rails control flow. As the example shows, the controller action completes all the processing required to render the view.

Essentially if you're looking to preserve information because you're redirecting. You will find it easier to render the view you're redirecting to.

EmFi