0

我正在修改一个微帖子 ruby​​ on rails 教程应用程序,并遇到了以下让我难过的问题:

用户有一个永久链接 URL,http://localhost:3000/users/exampleuser。访问者可以访问此网址并回答调查问卷。如果 exampleuser (current_user) 登录到他们自己的帐户,则以下代码有效。但是,如果您以访客身份前来,不需要登录,我会收到一个看起来像 Null User ID 的错误。我尝试分配正确的用户 ID 的所有尝试均未成功,尽管在我看来用户 ID 不再为空。

这是我收到的错误:

在 2012-02-24 20:28:56 -0500 开始 POST "/polls" for 127.0.0.1 由 PollsController#create 作为 HTML 参数处理:{"utf8"=>"✓", "authenticity_token"=>"ZE/ KXWCnBfE8PAn1CyAM51rnQI6z2Ut1UvHavEqSkZY=", "poll"=>{"overall_grade"=>"strong", "relevance"=>"strong", "personalization"=>"strong", "design"=>"strong", "value_proposition"= >"strong", "responder_name"=>"test", "responder_email"=>"test@test.com", "comments"=>"test"}, "commit"=>"提交成绩"} 用户负载 ( 0.2ms) SELECT "users".* FROM "users" WHERE "users"."id"IS NULL LIMIT 1 Completed 500 Internal Server Error in 47ms

RuntimeError (Called id for nil, 错误地是 4 -- 如果你真的想要 nil 的 id,使用 object_id): app/controllers/polls_controller.rb:5:in `create'

使用控制台我可以看到第一个用户(exampleuser)没问题。

ruby-1.9.2-p290 :001 > User.find(1)
  User Load (13.2ms)  SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1
  [["id", 1]] => #<User id: 1, name: "Example User", email: "example@railstutorial.org",
  created_at: "2012-02-23 17:27:45", updated_at: "2012-02-23 17:27:45",
  encrypted_password: "418b54481fffe05051621c500d69e44fd25573145c0b12e1860...", salt: 
  "57d9f6da0f6554e92c4180a469d5a1807c4a9dd46ce47c30b45...", admin: true, username: 
  "exampleuser", permalink: "exampleuser"> 

但是由于某种原因,这个逻辑在我的 Polls 控制器中不起作用。具体来说,我认为 Polls Controller 中的以下几行是问题所在:

  user_to_grade = User.find_by_id(@user.id)
  @poll = user_to_grade.polls.build(params[:poll])

任何见解将不胜感激。约翰

投票控制器

class PollsController < ApplicationController

  def create
    if current_user.blank?
      user_to_grade = User.find_by_id(@user.id)
      @poll = user_to_grade.polls.build(params[:poll])
    else
      @poll = current_user.polls.build(params[:poll])
    end    

    if @poll.save
      flash[:success] = "Pitch graded successfully!"
      redirect_to root_path
    else
      render 'pages/home'
    end
  end

end

民意调查模型

class Poll < ActiveRecord::Base
  attr_accessible :overall_grade, :personalization, :relevance, :value_proposition, :design, :other, :responder_name, :responder_email, :comments, :next_steps

  belongs_to :user

  validates :user_id, :presence => true
  validates :overall_grade, :presence => true

  default_scope :order => 'polls.created_at DESC'
end

用户模型

class User < ActiveRecord::Base
  attr_accessor :password
  attr_accessible :name, :username, :email, :password, :password_confirmation

  has_many :polls, :dependent => :destroy

  username_regex = /\A[\w\-]+\z/i
  email_regex = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i

  validates :name,  :presence   => true,
                    :length     => { :maximum => 50 }

  validates :username,  :presence   => true,
                        :length     => { :maximum => 50 },
                        :format     => { :with => username_regex },
                        :uniqueness => { :case_sensitive => false }

  validates :email, :presence   => true,
                    :format     => { :with => email_regex },
                    :uniqueness => { :case_sensitive => false }

  validates :password, :presence     => true,
                       :confirmation => true,
                       :length       => { :within => 6..40 }

  before_save :encrypt_password, :create_permalink

  #Returns true if the user's password matches the submitted password
  def has_password?(submitted_password)
    #Compare stored to submitted encrypted versions
    encrypted_password == encrypt(submitted_password)
  end

  def self.authenticate(email, submitted_password)
    #handles 2 scenarios: invalid email and a successful email, password mismatch implicitly since returns nil at end of method
    user = find_by_email(email)
    return nil if user.nil?
    return user if user.has_password?(submitted_password)
  end

  def self.authenticate_with_salt(id, cookie_salt)
    user = find_by_id(id)
    (user && user.salt == cookie_salt) ? user : nil
  end

  def to_param
    permalink
  end

  private
    def encrypt_password
      self.salt = make_salt unless has_password?(password)
      self.encrypted_password = encrypt(password)
    end

    def encrypt(string)
      secure_hash("#{salt}--#{string}")
    end

    def make_salt
      secure_hash("#{Time.now.utc}--#{password}")
    end

    def secure_hash(string)
      Digest::SHA2.hexdigest(string)
    end

    def create_permalink
      self.permalink = username.downcase
    end
end

用户控制器

class UsersController < ApplicationController
  before_filter :authenticate, :only => [:index, :edit, :update, :destroy]
  before_filter :correct_user, :only => [:edit, :update] 
  before_filter :admin_user,   :only => [:index, :destroy]

  def show
    @user = User.find_by_permalink(params[:id])
    @polls = @user.polls.paginate(:page => params[:page])
    @title = @user.name
    @poll = Poll.new
  end

  def new
    @user = User.new
    @title = "Sign up"
  end

  def create
    @user = User.new(params[:user])
    if @user.save
      #Handle a successful save.
      sign_in @user
      flash[:success] = "Signup Success welcome to Grademypitch!"
      redirect_to @user
    else
      @title = "Sign up"
      @user.password = ""
      render 'new'
    end
  end

  def edit
    @title = "Edit user"
  end

  def update
    @user = User.find_by_permalink(params[:id])
    if @user.update_attributes(params[:user])
      flash[:success] = "Profile updated."
      redirect_to @user
    else
      @title = "Edit user"
      render 'edit'
    end
  end

  def index
    @title = "All users"
    @users = User.paginate(:page => params[:page])
  end

  def destroy
    User.find_by_permalink(params[:id]).destroy
    flash[:success] = "User destroyed."
    redirect_to users_path
  end

  private
    def authenticate
      deny_access unless signed_in?
    end

    def correct_user
      @user = User.find_by_permalink(params[:id])
      redirect_to(root_path) unless current_user?(@user)
    end

    def admin_user
      redirect_to(root_path) unless current_user.admin?
    end
end

页面控制器

class PagesController < ApplicationController
  def home
    @title = "Home"
    @poll = Poll.new
  end

  def contact
    @title = "Contact"
  end

  def about
    @title = "About"
  end

  def help
    @title = "Help"
  end
end

路线

SampleApp::Application.routes.draw do  
  # removed when added session new/create/destroy....   get "sessions/new"

  #get "users/new" , can remove now that resources :users added cause it automatically adds all routes for users!

  resources :users
  resources :sessions, :only => [:new, :create, :destroy]
  resources :polls,    :only => [:new, :create]

  match '/signup',  :to => 'users#new'
  match '/signin',  :to => 'sessions#new'  
  match '/signout', :to => 'sessions#destroy'

  root :to => 'pages#home'

  match '/contact', :to => 'pages#contact'
  match '/about',   :to => 'pages#about'
  match '/help',    :to => 'pages#help'
end
4

2 回答 2

0

是的,您的第 5 行PollsController是问题所在:

user_to_grade = User.find_by_id(@user.id)

而且看起来您没有@userPollsController.

以下是相关部分:

if current_user.blank?
  user_to_grade = User.find_by_id(@user.id)
  @poll = user_to_grade.polls.build(params[:poll])
else
  @poll = current_user.polls.build(params[:poll])
end

当用户登录时,您正在对当前用户进行投票。当用户未登录时,您首先尝试找到与 @user (nil) 相同 id 的用户,但失败了,然后尝试对该用户进行投票。

对于未登录的用户,您希望的行为究竟是什么?他们应该能够完成创建动作吗?

于 2012-02-25T03:26:02.003 回答
0

所以我想通了。

第 1 步 - 我安装了 ruby​​-debug,它帮助我确定 @user.id 在到达投票控制器时为 nil。因此,在用户控制器和民意调查控制器之间,@user.id 被遗忘了。

第 2 步 - 我研究了会话功能作为一种可能的解决方案,因此我将以下区域修改为:

用户控制器

  def show
    @user = User.find_by_permalink(params[:id])
    @polls = @user.polls.paginate(:page => params[:page])
    @title = @user.name
    @poll = Poll.new

    if current_user.blank?
      session[:remember_token] = @user.id
    end
  end

在这里,我添加了一个会话令牌来记住用户页面中带有永久链接的用户 ID - 即用户/示例用户。因此,当我现在转到 Polls 控制器时,它可以调用会话令牌并使用以下代码找出我们来自哪个用户 ID...

投票控制器

    def create
        if current_user.blank?
          user_to_grade = User.find_by_id(session[:remember_token])
          @poll = user_to_grade.polls.build(params[:poll])
        else
          @poll = current_user.polls.build(params[:poll])
        end
    .
    .
    .

关键是 User.find_by_id(session[:remember_token])。这现在使用来自用户控制器的用户 id,不再是 nil,这解决了如何在控制器之间记住用户 id 的问题!

于 2012-02-27T03:10:59.950 回答