views:

297

answers:

2

Here's a simplified version of what I'm trying to do :

  1. Before any other actions are performed, present the user with a form to retrieve a string.
  2. Input the string, and then redirect to the default controller action (e.g. index). The string only needs to exist, no other validations are necessary.
  3. The string must be available (as an instance variable?) to all the actions in this controller.

I'm very new with Rails, but this doesn't seem like it ought to be exceedingly hard, so I'm feeling kind of dumb.

What I've tried : I have a before_filter redirecting to a private method that looks like

def check_string
  if @string
    return true
  else
    get_string
  end
end

the get_string method looks like

def get_string
  if params[:string]
    respond_to do |format|
      format.html {redirect_to(accounts_url)} # authenticate.html.erb
    end
  end

  respond_to do |format|
    format.html {render :action =>"get_string"} # get_string.html.erb
  end
end

This fails because i have two render or redirect calls in the same action. I can take out that first respond_to, of course, but what happens is that the controller gets trapped in the get_string method. I can more or less see why that's happening, but I don't know how to fix it and break out. I need to be able to show one form (View), get and then do something with the input string, and then proceed as normal.

The get_string.html.erb file looks like

<h1>Enter a string</h1>
<% form_tag('/accounts/get_string') do %>
<%= password_field_tag(:string, params[:string])%>
<%= submit_tag('Ok')%>
<% end %>

I'll be thankful for any help!

EDIT

Thanks for the replies...
@Laurie Young : You are right, I was misunderstanding. For some reason I had it in my head that the instance of any given controller invoked by a user would persist throughout their session, and that some of the Rails magic was in tracking objects associated with each user session. I can see why that doesn't make a whole lot of sense in retrospect, and why my attempt to use an instance variable (which I'd thought would persist) won't work. Thanks to you as well :)

+2  A: 

Part of the problem is that you aren't setting @string. You don't really need the before_filter for this at all, and should just be able to use:

def get_string
  @string = params[:string] || session[:string] 
  respond_to do |format|
    if @string  
      format.html {redirect_to(accounts_url)} # authenticate.html.erb
    else 
      format.html {render :action =>"get_string"} # get_string.html.erb
    end
  end
end

If you want the @string variable to be available for all actions, you will need to store it in the session.

Toby Hede
A: 

It looks like me like your missing a rails concept. Every single page the user sees is a different request.

I might have missunderstood what you are trying to do. But it seems to me you want the user to see two pages,

  1. In the first page they set a string variable
  2. In the second page they see a page that is somehow dependent on the variable set

The best way to do this would be to have to a before filter that checks for the existance of the varibale, and if its not set, redirects to them to the form, and otherwise continues

class MyController < ApplicationController::Base
  before_filter :require_string

  def require_string
    return true if @string #return early if called multiple times in one request
    if params['string'] or session['string']  #depending on if you set it as a URL or session var
      @string = (params['string'] or session['string'])
      return true
    end

    #We now know that string is not set
    redirect_to string_setting_url and return false #the return false prevents any futher processing in this request
  end
end

This is the basic idea behind how plugins like RestfulAuthentication work. In that case "string" is a login token (the user ID i think), is is stored in the session.

If you take a look at the login_required' action in authenticated_system.rb` from ResultfulAuth: it does basically this, though it has a few more error corrections, other stuff added in

Laurie Young