Rails:跨控制器的重复功能?谦虚的请求

时间:2010-05-19 03:47:58

标签: ruby-on-rails

所以我正在使用authlogic,我正在尝试将登录功能复制到欢迎页面,以便您可以通过restful url或只是转到主页面登录。不,我不知道我们是否会保留这个功能,但无论如何我想测试一下。这是错误消息:

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

代码如下。基本上,正在发生的是索引视图(第一个代码片段)将信息从表单发送到user_sessions控制器的create方法。在这一点上,从理论上讲,创造它应该只是提升,但事实并非如此。

请帮忙。请。我已经这样做了大约8个小时。我查了一下Google。我检查了IRC。我检查了我能找到的每本书。你甚至不必回答,如果你只是指出我正确的方向,我可以做咕噜咕噜的工作。

===编辑编辑编辑===

Sameera足以提供问题的答案。打开问题,但是组织应用程序的最佳方式是什么。将对象@user_sessions应用于可接受的before_filter中,还是有更多的rails-y方式来执行此操作?

欢迎#INDEX

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

应用程序控制器

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>

用户会话控制器

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

更详细的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'

3 个答案:

答案 0 :(得分:1)

您应该将以下方法添加到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

然后在WelcomeController中添加一个像这样的前置过滤器:

before_filter :require_user 

现在,访问WelcomeController的任何人都将被重定向到登录页面。您不必跨控制器复制功能。

请仔细阅读Authlogic设置教程:http://rdoc.info/projects/binarylogic/authlogic

答案 1 :(得分:0)

我认为你可以在WelcomeController中试试这个

class WelcomeController < ActionController::Base

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

  ..... 

end

在我看来,您正在尝试使用未在WelcomeController索引操作视图中定义的@user_session。

希望它有所帮助。

编辑#1

在我看来,在WelcomeController #index操作中提交表单后调用before_filter时会出现问题。

这段特殊代码对我来说很奇怪

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

我很确定UserSession.find会破裂。

希望这个编辑有所帮助。

编辑#2

我发现奇怪的另一件事是在受保护的方法new_session_object中:

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

使用UserSession.new创建params[:user_session]的原因是什么?

根据我的理解,您UserSessionController登录的流程是:

  1. before_filter :new_session_object被称为

  2. 它将返回false current_user因为它是新的 用户会话

  3. 它会设置@user_session变量 至 UserSession.new(params[:user_session])

  4. UserSessionController#new行动 被称为覆盖 @user_session变量 UserSession.new

  5. new.html.erb已呈现 包含登录表格

  6. before_filter :new_session_object is再次致电

  7. 它将返回false current_user因为它仍然是一个 新用户会话

  8. 它会设置@user_session变量 至 UserSession.new(params[:user_session])

  9. UserSessionController#create 再次召唤行动 将@user_session变量设置为 UserSession.new(params[:user_session]) 值。

  10. @user_session已保存并且已保存  用户会话成功  创建

  11. 但对于WelcomeController,它在步骤4中略有不同

    @user_session中使用的WelcomeController#index变量值来自before_filter的{​​{1}}调用变量赋值,此时UserSession.new(params[:user_session])值为params[:user_session],因此nil呈现@user_session = UserSession.new(nil)

    我不完全确定这是否会导致您的问题,但如果您运行ndex.html.erb并在使用{script/server --debugger时创建@user_session,则可能会帮助您解决此问题1}},特别是当表单发布到WelcomeController时。

答案 2 :(得分:0)

试试这个:

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

end