UsersController 中的 NoMethodError#show 更新用户属性后
NoMethodError in UsersController#show after updating users attributes
我正在使用 railstutorial.org 这本书。
我尝试按照本书第 7 章中的说明更新用户属性,但电子邮件变为零。我试过更新无济于事。这会在 UsersController#show 中产生一个 NoMethodError:undefined method `downcase' for nil: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
我需要帮助来解决这个问题。谢谢
我也在学习这个教程,所以我不假装是 Rails 专家。
也就是说,我刚刚回去查看了围绕
的第一个介绍的教程 material
before_save { email.downcase! }
语法,我在第 6 章 的末尾看到了这个 (listing 6.42)。
我很确定这对您不起作用,因为您的 UsersController 缺少 "New" 方法的定义:
def new
@user = User.new
end
我敢打赌你的@user 对象是 Nil 因为你还没有创建它的实例。顺便说一句,在本教程的这一点上,您还应该在 UsersController 中定义一个 Create 方法。
编辑: 如果您的问题仅限于 Rails 控制台中发生的事情,我同意您需要提供完整副本的评论控制台会话,以便人们提供完整的答案。
这是我的 Rails 教程项目中的 Rails 控制台会话示例:
调用控制台并让它知道我的用户模型:
$rails console
Loading development environment (Rails 4.2.2)
require './app/models/user'
=> true
创建一个名为 "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>
(注意:我的用户模型有更多属性,因为我快接近教程的结尾了。)
填写姓名和电子邮件的值:
spong.name = "Yo Dawg!"
=> "Yo Dawg!"
spong.email = "YoDaWG@dawg.COM"
=> "YoDaWG@dawg.COM"
请注意,我的初始电子邮件地址是大小写混合的。
调用小写方法:
spong.email.downcase
=> "yodawg@dawg.com"
这在控制台中对我有用。现在让我们试试 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
正如 Hartl 所说:
Note that if any of the validations fail, such as when a password is required to save a record (as implemented in Section 6.3), the call to update_attributes will fail.
所以让我试试这个命令的单数版本:
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"
并非电子邮件地址已在 INSERT 命令中转换为小写字母——完全符合预期,多亏了
before_save { email.downcase! }
我们的用户模型中有。
但是所有数据库 activity 是怎么回事?这是因为 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 的行为,我的数据库已更新;有点违反直觉,在此 "update" 过程中插入了一条记录,但这是因为我尚未将此(或第一条)记录保存到数据库中。
希望以上内容对您有所帮助。至少,我已经证明这确实可以通过控制台工作——即使使用以前的 'nil' 值(我在进行研究以尝试回答时学到了很多东西)。
我正在使用 railstutorial.org 这本书。 我尝试按照本书第 7 章中的说明更新用户属性,但电子邮件变为零。我试过更新无济于事。这会在 UsersController#show 中产生一个 NoMethodError:undefined method `downcase' for nil: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
我需要帮助来解决这个问题。谢谢
我也在学习这个教程,所以我不假装是 Rails 专家。
也就是说,我刚刚回去查看了围绕
的第一个介绍的教程 materialbefore_save { email.downcase! }
语法,我在第 6 章 的末尾看到了这个 (listing 6.42)。
我很确定这对您不起作用,因为您的 UsersController 缺少 "New" 方法的定义:
def new
@user = User.new
end
我敢打赌你的@user 对象是 Nil 因为你还没有创建它的实例。顺便说一句,在本教程的这一点上,您还应该在 UsersController 中定义一个 Create 方法。
编辑: 如果您的问题仅限于 Rails 控制台中发生的事情,我同意您需要提供完整副本的评论控制台会话,以便人们提供完整的答案。
这是我的 Rails 教程项目中的 Rails 控制台会话示例:
调用控制台并让它知道我的用户模型:
$rails console Loading development environment (Rails 4.2.2) require './app/models/user' => true
创建一个名为 "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>
(注意:我的用户模型有更多属性,因为我快接近教程的结尾了。)
填写姓名和电子邮件的值:
spong.name = "Yo Dawg!" => "Yo Dawg!" spong.email = "YoDaWG@dawg.COM" => "YoDaWG@dawg.COM"
请注意,我的初始电子邮件地址是大小写混合的。
调用小写方法:
spong.email.downcase => "yodawg@dawg.com"
这在控制台中对我有用。现在让我们试试 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
正如 Hartl 所说:
Note that if any of the validations fail, such as when a password is required to save a record (as implemented in Section 6.3), the call to update_attributes will fail.
所以让我试试这个命令的单数版本:
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"
并非电子邮件地址已在 INSERT 命令中转换为小写字母——完全符合预期,多亏了
before_save { email.downcase! }
我们的用户模型中有。
但是所有数据库 activity 是怎么回事?这是因为 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 的行为,我的数据库已更新;有点违反直觉,在此 "update" 过程中插入了一条记录,但这是因为我尚未将此(或第一条)记录保存到数据库中。
希望以上内容对您有所帮助。至少,我已经证明这确实可以通过控制台工作——即使使用以前的 'nil' 值(我在进行研究以尝试回答时学到了很多东西)。