creating an account with a username in devise

Hello, all. I have followed these links and have enabled a (current)
user to login with a username:

http://railscasts.com/episodes/209-introducing-devise
http://railscasts.com/episodes/210-customizing-devise
https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-sign-in-using-their-username-or-email-address

I want to allow a user to sign up with a username but am getting these
errors and don't know how to proceed. Notice the 'Email can't be blank'
error, even though I'm not wanting to accept an email for
authentication. It also doesn't recognize that I entered a password or
that they matched (even though they did):

Sign up
3 errors prohibited this user from being saved:
Email can't be blank
Password can't be blank
Password confirmation doesn't match Password

Please see attached devise view new.html.erb and devise model user.rb

Please let me know if you require any further information. Any help
would be greatly appreciated. Thanks.

Attachments:
http://www.ruby-forum.com/attachment/8539/new.html.erb
http://www.ruby-forum.com/attachment/8540/user.rb

I want to allow a user to sign up with a username but am getting these
errors and don't know how to proceed. Notice the 'Email can't be blank'
error, even though I'm not wanting to accept an email for
authentication.

Did you remember to set "config.authentication_keys = [:username]" in
the initializer? Show us at least the non-commented-out lines.

It also doesn't recognize that I entered a password or
that they matched (even though they did):

That sounds like you may be pulling out the wrong part of the params.
Can you show us the controller action and logged params? Or are you
just using the default Devise controllers?

-Dave

Did you remember to set "config.authentication_keys = [:username]" in
the initializer? Show us at least the non-commented-out lines.

$ grep -v \# config/initializers/devise.rb |grep .
Devise.setup do |config|
  config.mailer_sender = "password_reset@gloryhouseofprayer.com"
  require 'devise/orm/active_record'
  config.case_insensitive_keys = [ :username ]
  config.strip_whitespace_keys = [ :username ]
  config.stretches = Rails.env.test? ? 1 : 10
  config.use_salt_as_remember_token = true
  config.timeout_in = 30.minutes
  config.reset_password_within = 2.hours
  config.sign_out_via = :get
  config.authentication_keys = [ :username ]
  config.reset_password_keys = [ :username ]
  config.confirmation_keys = [ :username ]
end

That sounds like you may be pulling out the wrong part of the params.
Can you show us the controller action and logged params? Or are you
just using the default Devise controllers?

I apologize if I'm not following you, because I'm new to Ruby on Rails,
but Devise didn't install any Controller, nor did it add anything to the
default app/controller/application_controller.rb. So, I assume I'm
using the default. However I did add an entry to my application's
controller so I could authenticate before going to any page:

$ cat app/controllers/my_app_controller.rb
class MyAppController < ApplicationController
  before_filter :authenticate_user!
...

When I was looking through the logs (to respond to your "logged params"
question I found this error:
"Started POST "/users" for 127.0.0.1 at 2013-06-25 19:29:41 -0400
Processing by Devise::RegistrationsController#create as HTML
  Parameters: {"utf8"=>"✓",
"authenticity_token"=>"tltbt2w5FkZQbkbLqYaZIPiqk3J7VsdQIvKWFDCYLAs=",
"user"=>{"firstname"=>"bob", "lastname"=>"smith",
"password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"},
"commit"=>"Sign up"}
WARNING: Can't mass-assign protected attributes for User: password"

So, I googled it and saw references to removing the "attr_protected
:password" from the model (user.rb).

I did that and now only get the "Email can't be blank" error when trying
to sign up a user.

Here are the logs I get from rack when submitting the 'sign up' form:

Started POST "/users" for 127.0.0.1 at 2013-06-25 19:50:18 -0400
Processing by Devise::RegistrationsController#create as HTML
  Parameters: {"utf8"=>"✓",
"authenticity_token"=>"tltbt2w5FkZQbkbLqYaZIPiqk3J7VsdQIvKWFDCYLAs=",
"user"=>{"firstname"=>"bob", "lastname"=>"smith",
"password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"},
"commit"=>"Sign up"}
   (0.1ms) begin transaction
   (0.1ms) rollback transaction
  Rendered devise/shared/_links.erb (0.3ms)
  Rendered devise/registrations/new.html.erb within layouts/application
(3.6ms)
Completed 200 OK in 97ms (Views: 10.8ms | ActiveRecord: 0.2ms)

Started GET "/assets/application.css?body=1" for 127.0.0.1 at 2013-06-25
19:50:18 -0400
[2013-06-25 19:50:18] WARN Could not determine content-length of
response body. Set content-length of the response or set
Response#chunked = true

Started GET "/assets/bootstrap_and_overrides.css?body=1" for 127.0.0.1
at 2013-06-25 19:50:18 -0400
[2013-06-25 19:50:18] WARN Could not determine content-length of
response body. Set content-length of the response or set
Response#chunked = true

Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at 2013-06-25
19:50:18 -0400
[2013-06-25 19:50:18] WARN Could not determine content-length of
response body. Set content-length of the response or set
Response#chunked = true

Started GET "/assets/jquery_ujs.js?body=1" for 127.0.0.1 at 2013-06-25
19:50:18 -0400
[2013-06-25 19:50:18] WARN Could not determine content-length of
response body. Set content-length of the response or set
Response#chunked = true

Started GET "/assets/twitter/bootstrap/bootstrap-transition.js?body=1"
for 127.0.0.1 at 2013-06-25 19:50:18 -0400
[2013-06-25 19:50:18] WARN Could not determine content-length of
response body. Set content-length of the response or set
Response#chunked = true

Started GET "/assets/twitter/bootstrap/bootstrap-alert.js?body=1" for
127.0.0.1 at 2013-06-25 19:50:18 -0400
[2013-06-25 19:50:18] WARN Could not determine content-length of
response body. Set content-length of the response or set
Response#chunked = true

Started GET "/assets/twitter/bootstrap/bootstrap-modal.js?body=1" for
127.0.0.1 at 2013-06-25 19:50:18 -0400
[2013-06-25 19:50:18] WARN Could not determine content-length of
response body. Set content-length of the response or set
Response#chunked = true

Started GET "/assets/twitter/bootstrap/bootstrap-dropdown.js?body=1" for
127.0.0.1 at 2013-06-25 19:50:18 -0400
[2013-06-25 19:50:18] WARN Could not determine content-length of
response body. Set content-length of the response or set
Response#chunked = true

Started GET "/assets/twitter/bootstrap/bootstrap-scrollspy.js?body=1"
for 127.0.0.1 at 2013-06-25 19:50:18 -0400
[2013-06-25 19:50:18] WARN Could not determine content-length of
response body. Set content-length of the response or set
Response#chunked = true

Started GET "/assets/twitter/bootstrap/bootstrap-tab.js?body=1" for
127.0.0.1 at 2013-06-25 19:50:18 -0400
[2013-06-25 19:50:18] WARN Could not determine content-length of
response body. Set content-length of the response or set
Response#chunked = true

Started GET "/assets/twitter/bootstrap/bootstrap-tooltip.js?body=1" for
127.0.0.1 at 2013-06-25 19:50:18 -0400
[2013-06-25 19:50:18] WARN Could not determine content-length of
response body. Set content-length of the response or set
Response#chunked = true

Started GET "/assets/twitter/bootstrap/bootstrap-popover.js?body=1" for
127.0.0.1 at 2013-06-25 19:50:18 -0400
[2013-06-25 19:50:18] WARN Could not determine content-length of
response body. Set content-length of the response or set
Response#chunked = true

Started GET "/assets/twitter/bootstrap/bootstrap-button.js?body=1" for
127.0.0.1 at 2013-06-25 19:50:18 -0400
[2013-06-25 19:50:18] WARN Could not determine content-length of
response body. Set content-length of the response or set
Response#chunked = true

Started GET "/assets/twitter/bootstrap/bootstrap-carousel.js?body=1" for
127.0.0.1 at 2013-06-25 19:50:18 -0400
[2013-06-25 19:50:18] WARN Could not determine content-length of
response body. Set content-length of the response or set
Response#chunked = true

Started GET "/assets/twitter/bootstrap/bootstrap-collapse.js?body=1" for
127.0.0.1 at 2013-06-25 19:50:18 -0400
[2013-06-25 19:50:18] WARN Could not determine content-length of
response body. Set content-length of the response or set
Response#chunked = true

Started GET "/assets/twitter/bootstrap/bootstrap-typeahead.js?body=1"
for 127.0.0.1 at 2013-06-25 19:50:18 -0400
[2013-06-25 19:50:18] WARN Could not determine content-length of
response body. Set content-length of the response or set
Response#chunked = true

Started GET "/assets/twitter/bootstrap/bootstrap-affix.js?body=1" for
127.0.0.1 at 2013-06-25 19:50:18 -0400
[2013-06-25 19:50:18] WARN Could not determine content-length of
response body. Set content-length of the response or set
Response#chunked = true

Started GET "/assets/twitter/bootstrap.js?body=1" for 127.0.0.1 at
2013-06-25 19:50:18 -0400
[2013-06-25 19:50:18] WARN Could not determine content-length of
response body. Set content-length of the response or set
Response#chunked = true

Started GET "/assets/turbolinks.js?body=1" for 127.0.0.1 at 2013-06-25
19:50:18 -0400
[2013-06-25 19:50:18] WARN Could not determine content-length of
response body. Set content-length of the response or set
Response#chunked = true

Started GET "/assets/bootstrap.js?body=1" for 127.0.0.1 at 2013-06-25
19:50:18 -0400
[2013-06-25 19:50:18] WARN Could not determine content-length of
response body. Set content-length of the response or set
Response#chunked = true

Started GET "/assets/prayer_requests.js?body=1" for 127.0.0.1 at
2013-06-25 19:50:18 -0400
[2013-06-25 19:50:18] WARN Could not determine content-length of
response body. Set content-length of the response or set
Response#chunked = true

Started GET "/assets/application.js?body=1" for 127.0.0.1 at 2013-06-25
19:50:18 -0400
[2013-06-25 19:50:18] WARN Could not determine content-length of
response body. Set content-length of the response or set
Response#chunked = true

Did you remember to set "config.authentication_keys = [:username]" in
the initializer? Show us at least the non-commented-out lines.

$ grep -v \# config/initializers/devise.rb |grep .

Ah, we're obviously not dealing with a total programming-newbie here! :slight_smile:

  config.case_insensitive_keys = [ :username ]
  config.strip_whitespace_keys = [ :username ]

...

  config.authentication_keys = [ :username ]
  config.reset_password_keys = [ :username ]
  config.confirmation_keys = [ :username ]

Okay, so far so good. Just to be sure, I compared it with one of my
apps that uses username to log in, and the only other mention of
username I had was config.unlock_keys (which you might not be using at
all).

That sounds like you may be pulling out the wrong part of the params.
Can you show us the controller action and logged params? Or are you
just using the default Devise controllers?

I apologize if I'm not following you, because I'm new to Ruby on Rails,
but Devise didn't install any Controller,

Actually, it does, just not placed in with your own controllers. In
its own directory, it has controllers and views and so on. Gems
provide Rails additional places to find such things. Some, such as
Devise, also let you install stuff into your app's code dirs so that
you can mess with them. (I'm guessing you did that with its views, in
order to make it ask for first and last name instead of email.) Some
don't, and are meant to run strictly out of their own dirs (modulo the
configuration initializer).

I assume I'm using the default.

I'd agree.

However I did add an entry to my application's
controller so I could authenticate before going to any page:

$ cat app/controllers/my_app_controller.rb
class MyAppController < ApplicationController
  before_filter :authenticate_user!

That should be fine.

When I was looking through the logs (to respond to your "logged params"
question I found this error:

The rest of it looks good, confirming you're sending the right stuff
to the right place.

WARNING: Can't mass-assign protected attributes for User: password"

So, I googled it and saw references to removing the "attr_protected
:password" from the model (user.rb).

Yes, that's fairly important to understand. Another idea, though, is
to get a bit ahead of the curve, and use Rails 4 with its "strong
parameters". 4 was just released today, so it's now officially stable
so you can build with it confidently. Also, if you're trying to get
actual paid work in it, it's new enough that the competition will have
some struggles too, which evens the playing field a bit against
grizzled veterans like me. Oh, wait, never mind, stick with Rails 3,
better yet go check out Rails 2, pay no attention to the release no
longer behind the curtain.... :wink:

I did that and now only get the "Email can't be blank"
error when trying to sign up a user.

Ah, good progress.

Maybe there's still a validation looking for email in your User class?
Can you post that?

You could also go on a "search and destroy" mission: find all mentions
of email in your app and examine them to see if they could be the
cause. (Do you know about the "ack" utility?)

Come to think of it, there's a much simpler possibility; it may sound
stupid, but we've all done it. Maybe you didn't restart your Rails
server after modifying Devise. You need to do that to make it reread
the initializers, such as the one that tells Devise what fields to use
as keys.

-Dave

first of all, thanks man for helping me, I really appreciate it!

Ah, we're obviously not dealing with a total programming-newbie here!
:slight_smile:

:slight_smile: I said I was new to Ruby, not to programming. Started with Qbasic
on my commodore back in 1995 when I was 10. I know Assembly, C/C++,
Python, Shell, PHP. But I digress....

Actually, it does, just not placed in with your own controllers. In
its own directory, it has controllers and views and so on. Gems
provide Rails additional places to find such things. Some, such as
Devise, also let you install stuff into your app's code dirs so that
you can mess with them.

Here's what I ran to install devise:
rails generate devise:install
rails generate devise user
rails generate devise:views

(I'm guessing you did that with its views, in
order to make it ask for first and last name instead of email.)

Nope, I edited that myself because I couldn't find anything anywhere.

parameters". 4 was just released today

I am using rails 4:
$ rails -v
Rails 4.0.0.rc2

Also, if you're trying to get actual paid work in it

Ha! I better not be, my resume would read: "I googled stuff!"

Actually I want to get this (personal) project done and figured I'd go
back and learn why I did what I did and why it worked later. This goes
against everything in me but I simply don't have the time (right now) to
dedicate a month to fully learning ruby on rails before getting this
project done.

Maybe there's still a validation looking for email in your User class?
Can you post that?

$ grep -v \# app/models/user.rb |grep .
class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable, :recoverable,
:rememberable, :trackable, :validatable, :authentication_keys =>
[:username]
  validates_presence_of :firstname, :lastname, :unique => true
  after_validation :createUsername
  attr_accessible :username, :password, :password_confirmation,
:remember_me, :firstname, :lastname
  def createUsername
    firstnamePart=self.firstname[0,1].downcase
    lastnamePart=self.lastname[0,5].downcase
    username=lastnamePart + firstnamePart
    count=0
    while username.length != 7
      username=username + count.to_s
      count +=1
    end
    self.username=username
  end
  def self.find_first_by_auth_conditions(warden_conditions)
      conditions = warden_conditions.dup
      if login = conditions.delete(:login)
        where(conditions).where(["lower(username) = :value OR
lower(email) = :value", { :value => login.downcase }]).first
      else
        where(conditions).first
      end
    end
end

You could also go on a "search and destroy" mission: find all mentions
of email in your app and examine them to see if they could be the
cause.

$ grep -ri email *|egrep -v "#|log"
app/views/devise/mailer/unlock_instructions.html.erb:<p>Hello <%=
@resource.email %>!</p>
app/views/devise/mailer/confirmation_instructions.html.erb:<p>Welcome
<%= @resource.email %>!</p>
app/views/devise/mailer/reset_password_instructions.html.erb:<p>Hello
<%= @resource.email %>!</p>
app/views/devise/mailer/reset_password_instructions.html.erb:<p>If you
didn't request this, please ignore this email.</p>
config/locales/devise.en.yml: send_instructions: 'You will receive
an email with instructions about how to reset your password in a few
minutes.'
config/locales/devise.en.yml: send_instructions: 'You will receive
an email with instructions about how to confirm your account in a few
minutes.'
config/locales/devise.en.yml: send_paranoid_instructions: 'If your
e-mail exists on our database, you will receive an email with
instructions about how to confirm your account in a few minutes.'
config/locales/devise.en.yml: send_instructions: 'You will receive
an email with instructions about how to unlock your account in a few
minutes.'
config/locales/devise.en.yml: send_paranoid_instructions: 'If your
account exists, you will receive an email with instructions about how to
unlock it in a few minutes.'
Binary file db/development.sqlite3 matches
db/schema.rb: t.string "email",
default: "", null: false
db/schema.rb: add_index "users", ["email"], name:
"index_users_on_email", unique: true
Binary file
tmp/cache/assets/development/sprockets/d585a06e2ee6203ccb04c8b84150d14d
matches
Binary file
tmp/cache/assets/development/sprockets/13fe41fee1fe35b49d145bcc06610705
matches
Binary file
tmp/cache/assets/development/sprockets/8c2b061e379a23e7c4d207adcf992462
matches
Binary file
tmp/cache/assets/development/sprockets/357970feca3ac29060c1e3861e2c0953
matches
Binary file
tmp/cache/assets/development/sprockets/b7fc7a50cc3464d16f378714639f14e2
matches

(Do you know about the "ack" utility?)

a rails utility? Nope, never heard of an 'ack' utility.

Maybe you didn't restart your Rails server after modifying Devise.

I've only done that 500 times. Really, after every single change I made
I restarted rack, just in case.

that 'email' reference search looked lousy posting it directly, so here
it is in an attached file.

Attachments:
http://www.ruby-forum.com/attachment/8541/rails_app_email_references