【Rails学习笔记】用户模型

为什么要自己开发用户验证系统
基本上所有的 Web 应用程序都会需要某种登录和用户验证系统。所以 Web 框架大都有很多验证系统的实现方案,Rails 当然也不例外。用户验证及授权系统有很多,包括 Clearance、Authlogic、Devise 和 CanCan(还有一些不是专门针对 Rails 的基于 OpenID 和 OAuth 开发的系统)。所以你肯定就会问,为什么还要重复制造轮子,为什么不直接用现有的解决方案,而要自己开发呢?


首先,实践已经证明,大多数网站的用户验证系统都要对第三方代码库做一些定制和修改,这往往比重新开发一个验证系统的工作量还大。再者,现有的方案就像一个“黑盒”,你无法了解其中到底有些什么功能,而自己开发的话就能更好的理解实现的过程。而且,Rails 最近的更新,使开发验证系统变得很简单。最后,如果后续开发要用第三方代码库的话,因为自己开发过,所以你可以更好的理解其实现过程,便于定制功能。


创建“测试数据库”的正确命令:

$ bundle exec rake test:prepare

为某一列建立索引就需要改变数据库模型,在Rails中,这可以通过数据库迁移来实现。


let 方法
我们可以使用 RSpec 提供的 let 方法便捷的在测试中定义局部变量。let 方法的句法看起来有点怪,不过和变量赋值语句的作用是一样的。let 方法的参数是一个 Symbol,后面可以跟着一个块,块中代码的返回值会赋给名为 Symbol 代表的局部变量。也就是说:


let(:found_user) { User.find_by(email: @user.email) }
定义了一个名为 found_user 的变量,其值等于 find_by 的返回值。在这个测试用例的任何一个 before 或 it 块中都可以使用这个变量。使用 let 方法定义变量的一个好处是,它可以记住(memoize)变量的值。(memoize 是个行业术语,不是“memorize”的误拼写。)对上面的代码而言,因为 let 的备忘功能,found_user 的值会被记住,因此不管调用多少次 User 模型测试,find_by 方法只会运行一次。


最终的用户模型为:

class User < ActiveRecord::Base
	before_save { self.email = email.downcase }

	VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
	validates :name, presence: true, length: { maximum: 50}
	validates :email, presence:true, 
		format: {with: VALID_EMAIL_REGEX},
		uniqueness: {case_sensitive: false}
	
	has_secure_password
	validates :password, length: {minimum: 6}

end

而测试文件为:

require 'spec_helper'

describe User do
  before do
    @user = User.new(name: "haha", 
      email: "[email protected]",
      password: "foobar",
      password_confirmation: "foobar")
  end

  subject { @user }

  it {should respond_to(:name) }
  it {should respond_to(:email) }
  it {should respond_to(:password_digest)}
  it {should respond_to(:password)}
  it {should respond_to(:password_confirmation)}
  it {should respond_to(:authenticate)}

  it {should be_valid}


  describe "when name is not present" do 
  	before {@user.name = " "}
  	it {should_not be_valid}
  end

  describe "when email is not present" do 
  	before {@user.email = " "}
  	it {should_not be_valid}
  end

  describe "when name is too long" do
  	before { @user.name = 'a'*51 }
  	it {should_not be_valid}
  end

  describe "when email format is invalid" do
    it "should be invalid" do
      addresses = %w[user@foo,com user_at_foo.org example.user@foo.
                     foo@bar_baz.com foo@bar+baz.com]
      addresses.each do |invalid_address|
        @user.email = invalid_address
        expect(@user).not_to be_valid
      end
    end
  end

  describe "when email format is valid" do
    it "should be valid" do
      addresses = %w[[email protected] [email protected] [email protected] [email protected]]
      addresses.each do |valid_address|
        @user.email = valid_address
        expect(@user).to be_valid
      end
    end
  end

  describe "when email address is already taken" do
    before do
      user_with_same_email = @user.dup
      user_with_same_email.save
    end

    it { should_not be_valid }
  end

  describe "when password is not present" do
    before do
      @user = User.new(name: "Example User", email: "[email protected]",
                     password: " ", password_confirmation: " ")
    end
    it { should_not be_valid }
  end

  describe "when password doesn't match confirmation" do
    before { @user.password_confirmation = "mismatch" }
    it { should_not be_valid }
  end


  describe "with a password that's too short" do
    before { @user.password = @user.password_confirmation = "a" * 5 }
    it { should be_invalid }
  end

  describe "return value of authenticate method" do
    before { @user.save }
    let(:found_user) { User.find_by(email: @user.email) }

    describe "with valid password" do
      it { should eq found_user.authenticate(@user.password) }
    end

    describe "with invalid password" do
      let(:user_for_invalid_password) { found_user.authenticate("invalid") }

      it { should_not eq user_for_invalid_password }
      specify { expect(user_for_invalid_password).to be_false }
    end
  end

  


end



你可能感兴趣的:(数据库)