1

我能够创建具有相同名称和电子邮件的用户,即使我要求这些字段是唯一的。

查看数据库,可能会出现问题的条目被删除,然后创建一个新条目。

模型:

class User
  include Mongoid::Document
  extend Rolify
  rolify
  include Mongoid::Timestamps

  # Include default devise modules. Others available are:
  # :token_authenticatable, :confirmable,
  # :lockable, :timeoutable and :omniauthable
  devise :invitable, :database_authenticatable, :registerable, :confirmable,
         :recoverable, :rememberable, :trackable, :validatable

  ## Database authenticatable
  field :email,              :type => String, :default => ""
  field :encrypted_password, :type => String, :default => ""

  validates_presence_of :email
#  validates_presence_of :encrypted_password


  # override Devise method
  # no password is required when the account is created; validate password when the user sets one
  validates_confirmation_of :password
  def password_required?
    if !persisted? 
      !(password != "")
    else
      !password.nil? || !password_confirmation.nil?
    end
  end

  # override Devise method
  def confirmation_required?
    false
  end

  # override Devise method
  def active_for_authentication?
    confirmed? || confirmation_period_valid?
  end




  ## Recoverable
  field :reset_password_token,   :type => String
  field :reset_password_sent_at, :type => Time

  ## Rememberable
  field :remember_created_at, :type => Time

  ## Trackable
  field :sign_in_count,      :type => Integer, :default => 0
  field :current_sign_in_at, :type => Time
  field :last_sign_in_at,    :type => Time
  field :current_sign_in_ip, :type => String
  field :last_sign_in_ip,    :type => String

  # Confirmable
  field :confirmation_token,   :type => String
  field :confirmed_at,         :type => Time
  field :confirmation_sent_at, :type => Time
  field :unconfirmed_email,    :type => String # Only if using reconfirmable

  ## Lockable
  # field :failed_attempts, :type => Integer, :default => 0 # Only if lock strategy is :failed_attempts
  # field :unlock_token,    :type => String # Only if unlock strategy is :email or :both
  # field :locked_at,       :type => Time

  #invitable
  field :invitation_token, :type => String
  field :invitation_sent_at, :type => Time
  field :invitation_accepted_at, :type => Time
  field :invitation_limit, :type => Integer
  field :invited_by_id, :type => String
  field :invited_by_type, :type => String

  ## Token authenticatable
  # field :authentication_token, :type => String
  # run 'rake db:mongoid:create_indexes' to create indexes
  index({ email: 1 }, { unique: true, background: true })
  field :name, :type => String
  validates_presence_of :name
  validates_uniqueness_of :name, :email, :case_sensitive => false

  attr_accessible :role_ids, :as => :admin
  attr_accessible :name, :email, :password, :password_confirmation, :remember_me, :created_at, :updated_at


  # add a welcome email sender

  after_create :send_welcome_email


  def attempt_set_password(params)
    p = {}
    p[:password] = params[:password]
    p[:password_confirmation] = params[:password_confirmation]
    update_attributes(p)
  end

  # new function to determine whether a password has been set
  def has_no_password?
    self.encrypted_password.blank?
  end

  # new function to provide access to protected method pending_any_confirmation
  def only_if_unconfirmed
    pending_any_confirmation {yield}
  end

  private

  def send_welcome_email
    unless self.email.include?('@example.com') && Rails.env != 'test'
      UserMailer.welcome_email(self).deliver
      UserMailer.newusernotify(self).deliver
    end
  end


end

服务器日志:(一个名为“Bob”的用户已经存在,发送电子邮件至 test@test.com。在我请求创建一个名为“Sam”和 test@test.com 的新用户后,我得到的是:

Started POST "/users" for 127.0.0.1 at 2012-11-14 14:06:54 -0500
Processing by RegistrationsController#create as */*
  Parameters: {"user"=>{"email"=>"test@test.com", "name"=>"Sam"}}
  MOPED: 127.0.0.1:27017 COMMAND      database=admin command={:ismaster=>1} (6.2630ms)
  MOPED: 127.0.0.1:27017 QUERY        database=app_development collection=users selector={"$query"=>{"email"=>"test@test.com", "encrypted_password"=>""}, "$orderby"=>{:_id=>1}} flags=[:slave_ok] limit=-1 skip=0 fields=nil (5.0299ms)
  MOPED: 127.0.0.1:27017 DELETE       database=app_development collection=users selector={"_id"=>"50a3c974b8e764fc0d000005"} flags=[:remove_first] (0.1829ms)
before build resource
after build resource
  MOPED: 127.0.0.1:27017 QUERY        database=app_development collection=users selector={"email"=>"test@test.com"} flags=[:slave_ok] limit=1 skip=0 fields={:_id=>1} (1.9441ms)
  MOPED: 127.0.0.1:27017 QUERY        database=app_development collection=users selector={"name"=>/\ASam$/i} flags=[:slave_ok] limit=1 skip=0 fields={:_id=>1} (0.8898ms)
  MOPED: 127.0.0.1:27017 QUERY        database=app_development collection=users selector={"email"=>/\Atest@test\.com$/i} flags=[:slave_ok] limit=1 skip=0 fields={:_id=>1} (0.3989ms)
  MOPED: 127.0.0.1:27017 INSERT       database=app_development collection=users documents=[{"_id"=>"50a3ebceb8e764fc0d000006", "role_ids"=>[], "email"=>"test@test.com", "encrypted_password"=>"", "sign_in_count"=>0, "name"=>"Sam", "updated_at"=>2012-11-14 19:06:54 UTC, "created_at"=>2012-11-14 19:06:54 UTC}] flags=[] (1.3258ms)
  Rendered user_mailer/welcome_email.html.erb (0.0ms)
  Rendered user_mailer/welcome_email.text.erb (0.0ms)

另请注意:模型的 rspec 测试(如下)通过。为什么要设计删除用户,然后插入新用户?

require 'spec_helper'

describe User do

  before(:each) do
    @attr = { 
      :name => "Example User",
      :email => "user@example.com",
      :password => "foobar",
      :password_confirmation => "foobar"
    }
  end

  it "should create a new instance given a valid attribute" do
    User.create!(@attr)
  end

  it "should require an email address" do
    no_email_user = User.new(@attr.merge(:email => ""))
    no_email_user.should_not be_valid
  end

  it "should accept valid email addresses" do
    addresses = %w[user@foo.com THE_USER@foo.bar.org first.last@foo.jp]
    addresses.each do |address|
      valid_email_user = User.new(@attr.merge(:email => address))
      valid_email_user.should be_valid
    end
  end

  it "should reject invalid email addresses" do
    addresses = %w[user@foo,com user_at_foo.org example.user@foo.]
    addresses.each do |address|
      invalid_email_user = User.new(@attr.merge(:email => address))
      invalid_email_user.should_not be_valid
    end
  end

  it "should reject duplicate email addresses" do
    User.create!(@attr)
    user_with_duplicate_email = User.new(@attr)
    user_with_duplicate_email.should_not be_valid
  end

  it "should reject email addresses identical up to case" do
    upcased_email = @attr[:email].upcase
    User.create!(@attr.merge(:email => upcased_email))
    user_with_duplicate_email = User.new(@attr)
    user_with_duplicate_email.should_not be_valid
  end

  describe "passwords" do

    before(:each) do
      @user = User.new(@attr)
    end

    it "should have a password attribute" do
      @user.should respond_to(:password)
    end

    it "should have a password confirmation attribute" do
      @user.should respond_to(:password_confirmation)
    end
  end

  describe "password validations" do

    it "should require a password" do
      User.new(@attr.merge(:password => "", :password_confirmation => "")).
        should_not be_valid
    end

    it "should require a matching password confirmation" do
      User.new(@attr.merge(:password_confirmation => "invalid")).
        should_not be_valid
    end

    it "should reject short passwords" do
      short = "a" * 5
      hash = @attr.merge(:password => short, :password_confirmation => short)
      User.new(hash).should_not be_valid
    end

  end

  describe "password encryption" do

    before(:each) do
      @user = User.create!(@attr)
    end

    it "should have an encrypted password attribute" do
      @user.should respond_to(:encrypted_password)
    end

    it "should set the encrypted password attribute" do
      @user.encrypted_password.should_not be_blank
    end

  end

end

更新:我在 Registrations 控制器中插入了一些调试语句。非常有趣的是,它们都没有被触发——只有“构建资源之前”和“构建资源之后”,而不是“FIRST IF”、“SECOND IF”或“THIRD IF”。为什么会这样?

  class RegistrationsController < Devise::RegistrationsController
  # override #create to respond to AJAX with a partial
    def create
      logger.debug "before build resource"
      build_resource
      logger.debug "after build resource"
      if resource.save
        if resource.active_for_authentication?
          sign_in(resource_name, resource)
          (render(:partial => 'thankyou', :layout => false) && return)  if request.xhr?
          logger.debug "FIRST IF"
          respond_with resource, :location => after_sign_up_path_for(resource)
        else
          expire_session_data_after_sign_in!
          (render(:partial => 'thankyou', :layout => false) && return)  if request.xhr?
          logger.debug "SECOND IF"
          respond_with resource, :location => after_inactive_sign_up_path_for(resource)
        end
      else
        logger.debug "THIRD IF"
        clean_up_passwords resource
        render :action => :new, :layout => !request.xhr?
      end
    end

    protected

    def after_inactive_sign_up_path_for(resource)
      # the page prelaunch visitors will see after they request an invitation
      '/thankyou.html'
    end

    def after_sign_up_path_for(resource)
      # the page new users will see after sign up (after launch, when no invitation is needed)
  #    '/thankyou.html'
      redirect_to root_path
    end

  end
4

0 回答 0