I am using the railstutorial.org book. I tried updating the user attributes as written in Chapter 7 of the book, but the email became nil. I have tried updating to no avail. This produces a NoMethodError in UsersController#show: undefined method `downcase' for nil:NilClass.
Here is the show.html.erb
<% provide(:title, @user.name) %>
<h1>
<%= gravatar_for @user %>
<%= @user.name %>
</h1>
Users helper
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
User Controller
class UsersController < ApplicationController
def new
end
def show
@user = User.find(params[:id])
end
end
User model
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
Please I need help to fix this. Thanks.
I'm also following this tutorial, so I don't pretend to be a Rails expert.
That said, I just went back and reviewed the tutorial material surrounding the first introduction of the
before_save { email.downcase! }
syntax, and I see this at the end of Chapter 6 (listing 6.42).
I'm pretty sure this isn't working for you because your UsersController is missing a definition of the "New" method:
def new
@user = User.new
end
I'm wiling to bet that your @user object is Nil because you haven't create an instance of it yet. BTW, at this point in the tutorial, you should have also defined a Create method in UsersController.
EDIT: If your problems are limited to what is happening in the Rails console, I agree with the comments that you need to provide a complete transcript of your console session in order for folks to provide a complete answer.
Here's an example Rails console session from within my Rails Tutorial project:
Invoke the console and make it aware of my User model:
$rails console
Loading development environment (Rails 4.2.2)
require './app/models/user'
=> true
Create a User instance named "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>
(Note: My User model has more attributes because I am toward the end of the Tutorial.)
Populate values for name and e-mail:
spong.name = "Yo Dawg!"
=> "Yo Dawg!"
spong.email = "YoDaWG@dawg.COM"
=> "YoDaWG@dawg.COM"
Note that my initial e-mail address is mixed case.
Invoke the downcase method:
spong.email.downcase
=> "yodawg@dawg.com"
This is working for me in the console. Now let's try the update_attributes method:
spong.update_attributes(name: "The Dude", email: "dude@AbideS.org")
This is straight out of the tutorial, but it doesn't work for me, because at this point in my journey, I have implemented features that prevent this kind of update:
(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
As Hartl says:
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.
So let me try the singular version of this command:
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"
Not that the e-mail address is already converted to lower case in the INSERT command--exactly as expected, thanks to that
before_save { email.downcase! }
we have in our User model.
But what's with all the DB activity? This is because update_attributes updates a single attribute and saves the record without going through the normal validation procedure (which is why I am able to do this). While research this, I found this excellent discussion about update_attribute and update_attributes. Great stuff!
OK, so what happens if we try to call update_attribute when the (existing) e-mail address is blank? Let's see:
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>
Everything in newUser is nil. Let's try to update the e-mail address:
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
Again, because of the behavior of update_attribute/update_attributes, my database is updated; somewhat counterintuitively, a record is inserted during this "update" process, but this is because I had not yet saved this (or the first) record to the DB.
I hope all this helps. At a minimum, I have demonstrated that this DOES work via the console--even with previously 'nil' values (and I learned a ton while doing the research to attempt an answer).