UsersController#中的NoMethodError在更新用户属性后显示

时间:2015-07-28 03:42:41

标签: ruby-on-rails railstutorial.org nomethoderror

我正在使用railstutorial.org书。 我尝试更新用户属性,如本书第7章所述,但电子邮件变为零。我试过更新无济于事。这在UsersController中产生NoMethodError#show:nil的未定义方法`downcase':NilClass。

这是show.html.erb

<% provide(:title, @user.name) %>
<h1>
  <%= gravatar_for @user %>
  <%= @user.name %>
</h1>

用户帮助

module UsersHelper
  # Returns the Gravatar of the given user.
  def gravatar_for(user)
    gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
    gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}"
    image_tag(gravatar_url, alt: user.name, class: "gravatar")
  end
end

用户控制器

class UsersController < ApplicationController
  def new
  end

  def show
    @user = User.find(params[:id])
  end
end

用户模型

class User < ActiveRecord::Base
  before_save { email.downcase! }
  validates :name, presence: true, length: { maximum: 50 }
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
  validates :email, presence: true,
                    format: { with: VALID_EMAIL_REGEX },
                    uniqueness: { case_sensitive: false }
  has_secure_password
  validates :password, presence: true, length: { minimum: 6 }
end

我需要帮助来解决这个问题。感谢。

1 个答案:

答案 0 :(得分:0)

我也在关注本教程,所以我不假装成为Rails专家。

那就是说,我回过头来回顾一下第一次介绍

的教程材料
before_save { email.downcase! }

语法,我在第6章listing 6.42)的末尾看到了这一点。

我很确定这不适合你,因为你的UsersController缺少“新”方法的定义:

    def new
       @user = User.new
    end

我想打赌你的@user对象是Nil,因为你还没有创建它的实例。顺便说一句,在本教程的这一点上,您还应该在UsersController中定义一个Create方法。

编辑:如果您的问题仅限于Rails控制台中发生的问题,我同意您提供控制台会话的完整记录所需的注释,以便人们提供完整答案。

以下是我的Rails Tutorial项目中的Rails控制台会话示例:

  1. 调用控制台并使其了解我的用户模型:

    $rails console  
    Loading development environment (Rails 4.2.2)  
    require './app/models/user'  
    => true  
    
  2. 创建名为“spong”的用户实例

    **spong = User.new**  
    => <User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, password_digest: nil, remember_digest: nil, admin: nil, activation_digest: nil, activated: false, activated_at: nil>  
    
  3. (注意:我的用户模型有更多属性,因为我接近教程的末尾。)

    1. 填充姓名和电子邮件的值:

      spong.name = "Yo Dawg!"  
      => "Yo Dawg!"  
      spong.email = "YoDaWG@dawg.COM"  
      => "YoDaWG@dawg.COM"
      
    2. 请注意,我的初始电子邮件地址是大小写混合的。

      1. 调用downcase方法:

        spong.email.downcase 
        => "yodawg@dawg.com"  
        
      2. 这在控制台中对我有用。现在让我们尝试使用update_attributes方法:

            spong.update_attributes(name: "The Dude", email: "dude@AbideS.org")
        

        这直接来自tutorial,但它对我不起作用,因为在我的旅程中,我已经实现了阻止此类更新的功能:

            (6.5ms)  begin transaction  
            User Exists (0.5ms)  SELECT  1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER('dude@AbideS.org') LIMIT 1  
            User Exists (0.2ms)  SELECT  1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER('dude@AbideS.org') LIMIT 1  
            (0.1ms)  rollback transaction  
            => false  
        

        正如哈特尔所说:

          

        请注意,如果任何验证失败,例如需要密码来保存记录(如第6.3节中所述),则对update_attributes的调用将失败。

        1. 让我试试这个命令的单数版本:

          spong.update_attribute( :email, "dude@AbideS.org")  
          (3.7ms)  begin transaction  
          SQL (4.0ms) INSERT INTO "users" ("name", "email", "created_at", "updated_at", "activation_digest") VALUES (?, ?, ?, ?, ?)  [["name", "The Dude"], ["email", "dude@abides.org"], ... ]  
          (1.2ms)  commit transaction  
          ==> true  
          spong.email 
          => "dude@abides.org"
          
        2. 并不是说INSERT命令中的电子邮件地址已经转换为小写 - 完全符合预期,这要归功于

          before_save { email.downcase! }
          

          我们的用户模型。

          但是所有数据库活动都是什么?这是因为update_attributes更新了单个属性,而保存了记录,而没有经过正常的验证程序(这就是为什么我能够这样做)。在研究这个时,我发现了this excellent discussion关于update_attribute和update_attributes。好东西!

          好的,如果我们在(现有的)电子邮件地址为空时尝试调用update_attribute会发生什么?我们来看看:

              newUser = User.new  
              => #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, password_digest: nil, remember_digest: nil, admin: nil, activation_digest: nil, activated: false, activated_at: nil>
          

          newUser中的所有内容都是零。让我们尝试更新电子邮件地址:

              newUser.update_attribute(:email, "cOnFuSed@MixecCase.com")**  
              (1.2ms)  begin transaction  
              SQL (3.9ms)  INSERT INTO "users" ("email", "created_at", "updated_at", "activation_digest") VALUES (?, ?, ?, ?)  [["email", "confused@mixeccase.com"], ...]  
              (0.9ms)  commit transaction  
              => true
          

          同样,由于update_attribute / update_attributes的行为,我的数据库已更新;有点违反直觉,在这个“更新”过程中会插入一条记录,但这是因为我还没有将这个(或第一个)记录保存到数据库中。

          我希望这一切都有帮助。至少,我已经证明这可以通过控制台工作 - 即使以前的'零'值(我在做研究时学到了很多东西来尝试答案)。