我正在使用railstutorial.org这本书。我尝试按照书中第7章的内容更新用户属性,但是邮件变成了nil。我已经尝试更新,但无济于事。这会在userscontroller# show: undefined method ' downcase' for nil:NilClass中产生NoMethodError。
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-zd-]+(.[a-zd-]+)*.[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专家。
也就是说,我只是回顾了关于
的第一次介绍的教程材料before_save { email.downcase! }
语法,我在第6章的末尾看到了这一点(清单6.42)。
我很确定这对你不起作用,因为你的UsersController缺少"New"方法的定义:
def new
@user = User.new
end
我敢打赌你的@user对象是Nil,因为你还没有创建它的实例。顺便说一句,在本教程中,您还应该在UsersController中定义一个Create方法。
EDIT:如果您的问题仅限于Rails控制台中发生的事情,我同意您需要提供控制台会话的完整记录以便人们提供完整的答案的评论。
下面是我的Rails教程项目中的一个示例Rails控制台会话:
调用控制台并使其意识到我的用户模型:
$rails console Loading development environment (Rails 4.2.2) require './app/models/user' => true
创建一个名为"spong"的User实例
**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"
调用downcase方法:
spong.email.downcase => "yodawg@dawg.com"
那么让我试试这个命令的单数版本:
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"
请注意,我的初始电子邮件地址是大小写混合的。
这在控制台中为我工作。现在让我们试试update_attributes方法:
spong.update_attributes(name: "The Dude", email: "dude@AbideS.org")
这是直接从教程出来的,但它不适合我,因为在我的旅程中,我已经实现了防止这种更新的功能:
(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的调用将失败。
并不是说在INSERT命令中已经将电子邮件地址转换为小写——正是由于
before_save { email.downcase! }
在我们的User模型中
但是DB活动是怎么回事?这是因为update_attributes更新了单个属性,而保存了记录,而无需经过正常的验证过程(这就是我能够这样做的原因)。在研究的过程中,我发现了关于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中的所有内容都是nil。让我们尝试更新电子邮件地址:
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的行为,我的数据库被更新;有点违反直觉的是,在这个"更新"过程中插入了一条记录,但这是因为我还没有将这条(或第一条)记录保存到DB。
我希望这些都有帮助。至少,我已经证明了这确实可以通过控制台工作——即使之前的值是"nil"(我在做研究时学到了很多)。