views:

75

answers:

3

So I'm working with authlogic, and I'm trying to duplicate the login functionality to the welcome page, so that you can log in by restful url or by just going to the main page. No, I don't know if we'll keep that feature, but I want to test it out anyway. Here's the error message:

RuntimeError in Welcome#index Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id

The code is below. Basically, what's happening is the index view (the first code snippet) is sending the information from the form to the create method of user_sessions controller. At this point, in theory, it create should just pick up, but it doesn't.

PLEASE help. Please. I've been doing this for about 8 hours. I checked Google. I checked IRC. I checked every book I could find. You don't even have to answer, I can to the grunt work if you just point me in the right direction.

===EDIT EDIT EDIT===

Sameera was good enough to provide the answer to the problem. Open question, though is what the best way to organize the app is. Is applying the object @user_sessions in a before_filter acceptable, or is there a more rails-y way of doing this?

WELCOME#INDEX

<% form_for @user_session, :url => user_sessions_path do |f| %>
    <%= f.text_field :email %><br />
<%= f.password_field :password %>
<%= submit_tag 'Login' %>
<% end %>

APPLICATION CONTROLLER

class ApplicationController < ActionController::Base
  helper :all # include all helpers, all the time
  protect_from_forgery # See ActionController::RequestForgeryProtection for details
  # Scrub sensitive parameters from your log
  # filter_parameter_logging :password
    helper_method :current_user_session, :current_user
    before_filter :new_session_object
protected
    def new_session_object
        unless current_user
        @user_session = UserSession.new(params[:user_session])
    end
end
private
def current_user_session
    return @current_user_session if defined?(@current_user_session)
    @current_user_session = UserSession.find
end
def current_user
    return @current_user if defined?(@current_user)
    @current_user = current_user_session && current_user_session.record
end
end<pre></code>

USER SESSIONS CONTROLLER

class UserSessionsController < ApplicationController
  def new
    @user_session = UserSession.new
  end

  def create
    @user_session = UserSession.new(params[:user_session])
    if @user_session.save
      flash[:notice] = "Logged in"
      redirect_to root_url
    else
      render :controller => 'user_sessions', :action => 'new'
    end
  end

  def destroy
    @user_session = UserSession.find
    @user_session.destroy
    flash[:notice] = "Logged out"
    redirect_to root_url
  end
end

A more detailed STACK TRACE

1: <h1>Welcome#index</h1>
2: <p>Find me in app/views/welcome/index.html.erb</p>
3: 
4: <% form_for @user_session, :url => user_sessions_path do |f| %>
5:  <%= f.text_field :email %><br />
6:      <%= f.password_field :password %>
7:  <%= submit_tag 'Login' %>

Application Trace | Framework Trace | Full Trace
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/gems/1.8/gems/actionpac -2.3.5/lib/action_controller/record_identifier.rb:76:in `dom_id'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_view/helpers/record_identification_helper.rb:16:in `dom_id'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_view/helpers/form_helper.rb:293:in `apply_form_for_options!'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_view/helpers/form_helper.rb:277:in `form_for'
/Users/alex/Desktop/anglic/app/views/welcome/index.html.erb:4:in `_run_erb_app47views47welcome47index46html46erb'
A: 

I think you can try this in your WelcomeController

class WelcomeController < ActionController::Base

  def index
    @user_session = UserSession.new
    .....
  end

  ..... 

end

It seems to me that you are trying to use @user_session which is not defined in the view of WelcomeController index action.

Hopefully it helps.

EDIT #1

It seems to me that the problem occur when the before_filter was called, after you submit the form in the WelcomeController#index action.

This particular section of code is strange to me

class ApplicationController < ActionController::Base

  .....
  private
  def current_user_session
    return @current_user_session if defined?(@current_user_session)
    @current_user_session = UserSession.find
  end
  .....

end

I am quite sure UserSession.find will break.

Hopefully this edit helps.

EDIT #2

Another thing that I found strange is inside the protected method new_session_object:

protected
    def new_session_object
        unless current_user
        @user_session = UserSession.new(params[:user_session])
    end
end

Any reason why the UserSession.new was created with params[:user_session] ?

The flow for your UserSessionController login as far as I understand it is:

  1. before_filter :new_session_object is called

  2. it will return false for current_user since it is a new user session

  3. it will set @user_session variable to UserSession.new(params[:user_session]) value

  4. UserSessionController#new action is called which override @user_session variable to UserSession.new

  5. new.html.erb is rendered containing the form for login

  6. before_filter :new_session_object is called again

  7. it will return false for current_user since it is still a new user session

  8. it will set @user_session variable to UserSession.new(params[:user_session]) value

  9. UserSessionController#create action is called which will again set the @user_session variable to UserSession.new(params[:user_session]) value.

  10. @user_session is saved and the user session is successfully created

BUT for the WelcomeController it is subtly different in step 4

The @user_session variable value that is used in the WelcomeController#index came from the before_filter call variable assignment of UserSession.new(params[:user_session]), at that point the params[:user_session] value is nil, so the @user_session = UserSession.new(nil) when the index.html.erb was rendered.

I am not entirely sure if this is the thing that cause your problem, but it may help you to troubleshoot this issue if you run script/server --debugger and step trough the creation of @user_session when using WelcomeController, specially when the form is posted to UserSessionController#create.

SamChandra
Thanks for the response! Two things. First, it isn't that the form doesn't load (the before_filter in the appcontroller makes that instance variable for us), it's that when we submit the order, @user_session should propagate from Welcome#index to UserSessions#create. Instead, we get the error above. And second, I'd hate to duplicate the code in the acutal UserSessionsController, which does exactly what your code indicates. Is there a way to make is so that I can just call UserSessionsController's version of new instead?Thanks again for the response.
Alex
Take a look at the edited answer
SamChandra
Thanks once again for the response! So my question then would be, why does it NOT break if I issue a POST :create from within the UserSessions controller? The only time I get this error is when I try to POST :create from a different controller. Also, that's an internal method that Authlogic needs to maintain sessions, and I think it gets run at least once every request. So I would expect the error to manifest more than it has, though I could be wrong about that.
Alex
Take a look at the edited answer #2
SamChandra
+1  A: 

You should add the following method to the ApplicationController:

def require_user
    unless current_user
        flash[:notice] = "You must be logged in to access this page!"
        redirect_to :controller => "user_sessions", :action => "new"            
        return false
    end
end

Then in the WelcomeController add a before filter like this:

before_filter :require_user 

Now, anybody accessing WelcomeController will be redirected to the login page. You don't have to duplicate the functionality across controllers.

Please go through the Authlogic set-up tutorial for details: http://rdoc.info/projects/binarylogic/authlogic

sam
Hi, Syed. Sorry, not to be difficult, but every ounce of work you cause users is another excuse for them to just leave the site completely. It's not that I don't know I can't before_filter the users, it's that I frankly don't want to.
Alex
Also, thanks for the site, but I have in fact scoured it. My authentication system, for example, is highly customized. Also, I would not dream of bothering the good folks of SO unless I felt I had exhausted all solutions at my disposal.
Alex
A: 

Hi Alex

try this

form_for :user_session, @user_session, :url => user_session_path(@user_session)} do |f|

end

cheers, sameera

sameera207
WOOO! IT WORKS! Sameera, sir (or ma'am!), you are an amazing and beautiful person. Please accept my most sincere and boisterous thanks. I give you rights to my firstborn. May all the gods in heaven shower you with money and fame.
Alex
Hi,Nice to see you found my answer useful :Dcheers,sameera
sameera207
Hi Alex,I got this example from action view examples. (/usr/lib/ruby/gems/1.8/gems/actionpack-2.2.2/lib/action_view/helpers/form_helper)If possible try to use netbeans (I'm using 6.9) and it gives automatic code completion and examples as you typeI think its a great IDE cheers,sameera
sameera207