2015-05-16 171 views
0

設計用戶註冊和登錄。水豚和管理員用戶權限(和設計)的問題

使用rails控制檯設置管理員(將admin布爾值設置爲true)。

Rspec和FactoryGirl。

不幸的是,我寫我的應用程序編寫測試之前(最好的教訓學到了艱辛的道路)。我現在正在學習rspec併爲應用程序編寫測試套件。

我有控制器的權限和查看權限設置,管理員和非管理員,這在實踐中做的工作(我知道這通過徹底的瀏覽器手動測試)。

在這種情況下,我在當用戶登錄其上顯示,也是一個管理員的報頭中的「系統管理員」鏈接。

我StaticPagesController也有一個有效的before_action設置所以,除非他們登錄,也是管理員沒有人可以訪問管理頁面。

我寫了一些這方面的測試,以爲我擁有排序,直到我注意到,更改到包含這些測試的具體/功能規格文件時,衛兵只運行這些測試,並將它們傳遞。但是,當我運行整個測試套件時,那些相同的測試失敗。我完全被這個困惑了。

我認爲這可能與Devise有關,但我只是不知道。

規格/功能/ user_and_role_spec.rb

require 'rails_helper' 

def manually_create_user 
    visit new_user_registration_path 
    fill_in('user_first_name', :with => 'Test') 
    fill_in('user_last_name', :with => 'User') 
    fill_in('user_email', :with => '[email protected]') 
    fill_in('user_password', :with => 'testuser') 
    click_button('Sign up') 
end 

def create_user_and_login_as(type) 
    user = FactoryGirl.create(type) 
    visit(new_user_session_path) 
    fill_in('user_email', :with => user.email) 
    fill_in('user_password', :with => user.password) 
    click_button('Log in') 
end 


describe 'with users and roles' do 

    context "if user is not an admin" do 

     it "does not allow any user to visit the admin page if not logged-in" do 
      visit(admin_path) 
      expect(current_path).to eq(root_path) 
     end 

     it "does not allow a new user to visit the admin page" do 
      manually_create_user 
      visit(admin_path) 
      expect(current_path).to eq(root_path) 
     end 

     it "does not allow a student to visit the admin page" do 
      create_user_and_login_as(:student) 
      visit admin_path 
      expect(current_path).to eq(root_path) 
     end 

     it "does not allow a teacher to visit the admin page" do 
      create_user_and_login_as(:teacher) 
      visit admin_path 
      expect(current_path).to eq(root_path) 
     end 

    end 


    context "if user is an admin" do 

     it "allows an admin user to visit the admin page" do 
      create_user_and_login_as(:admin_user) 
      click_link 'Admin' 
      expect(current_path).to eq(admin_path) 
     end 

     it "allows a teacher_admin to visit the admin page" do 
      create_user_and_login_as(:teacher_admin_user) 
      click_link 'Admin' 
      expect(current_path).to eq(admin_path) 
     end 

    end 

end 

在上下文中的測試:「如果用戶是不是管理員」運行完整的測試套件時全部失敗。他們都失敗了同樣的錯誤:

Failure/Error: expect(current_path).to eq(root_path) 

     expected: "/" 
      got: "/admin" 

     (compared using ==) 

其中,對我來說,意味着管理頁面訪問,當它應該不會遲到了。在我的瀏覽器中,無法看到管理頁面鏈接,也不能通過手動輸入網址訪問頁面,除非用戶已登錄並且是管理員。

的背景下,「如果用戶是管理員」運行完整的測試套件時,全部通過測試。

規格/工廠/ users.rb的:

require 'faker' 

FactoryGirl.define do 
    factory :user do |f| 
     f.first_name { Faker::Name.first_name } 
     f.last_name  { Faker::Name.last_name } 
     f.email   { Faker::Internet.email } 
     f.password  { Faker::Internet.password(8) } 
     f.admin   false 

     trait :student do 
      type "Student" 
     end 

     trait :teacher do 
      type "Teacher" 
     end 

     trait :admin do 
      admin true 
     end 

     factory :admin_user,   traits: [:admin] 
     factory :student,    traits: [:student] 
     factory :teacher,    traits: [:teacher] 
     factory :teacher_admin_user, traits: [:teacher, :admin] 

    end 
end 

static_pages_controller.rb:

class StaticPagesController < ApplicationController 
    before_action :admin?, only: [:admin] 

    def home 
    @testimonials = Testimonial.all 
    end 

    def admin 
    @groups = Group.all 

    @users = User.all 

    @students = Student.all 

    @teachers = Teacher.all 
    end 

    private 

    def admin? 
    unless signed_in? and current_user.admin == true 
     redirect_to root_path, notice: "You must be a signed-in admin to view this page" 
    end 
    end 

end 

static_pages_helper.rb:

module StaticPagesHelper 

    def allowed_to_see_admin_link? 
     signed_in? && current_user.admin 
    end 

end 

型號/ user.rb:

class User < ActiveRecord::Base 
    # Include default devise modules. Others available are: 
    # :confirmable, :lockable, :timeoutable and :omniauthable 
    devise :database_authenticatable, :registerable, 
     :recoverable, :rememberable, :trackable, :validatable 

    validates :first_name, presence: true 
    validates :last_name, presence: true 
    validates :admin, inclusion: { in: [true, false] } 

    scope :newest_first, -> { order("created_at DESC") } 
    scope :order_by_first_name, -> { order("first_name") } 

    def full_name 
    "#{first_name} #{last_name}" 
    end 

    def unassigned? 
    type != "Student" and type != "Teacher" 
    end 

    def can_view_materials? 
    admin || type == "Teacher" || type == "Student" && groups.any? # So only current students can view the Materials page. 
    end 

    def testimonial_owner?(testimonial) 
    id == testimonial.student_id 
    end 

end 

_header.html的相關部分。ERB部分:

<ul class="nav navbar-nav navbar-right"> 
     <% if allowed_to_see_admin_link? %> 
      <li><%= link_to "Admin", admin_path %></li> 
     <% end %> 
     </ul> 

的Gemfile:

gem 'rails', '4.2.0' 
gem 'bootstrap-sass', '~> 3.3.3' 
gem 'sass-rails', '~> 5.0' 
gem 'uglifier', '>= 1.3.0' 
gem 'coffee-rails', '~> 4.1.0' 
gem 'jquery-rails' 
gem 'turbolinks' 
gem 'jbuilder', '~> 2.0' 
gem 'sdoc', '~> 0.4.0', group: :doc 
gem 'devise' 

group :development, :test do 
    gem 'sqlite3' 
    gem 'byebug' 
    gem 'web-console', '~> 2.0' 
    gem 'spring' 
    gem 'better_errors' 
    gem 'binding_of_caller' 
    gem 'rspec-rails' 
    gem 'guard-rspec', require: false 
    gem 'factory_girl_rails' 
end 

group :test do 
    gem 'faker' 
    gem 'capybara' 
    gem 'launchy' 
    gem 'database_cleaner' 
end 

group :production do 
    gem 'pg' 
    gem 'rails_12factor' 
end 

用戶模式:

create_table "users", force: :cascade do |t| 
    t.string "email",     default: "", null: false 
    t.string "encrypted_password",  default: "", null: false 
    t.string "reset_password_token" 
    t.datetime "reset_password_sent_at" 
    t.datetime "remember_created_at" 
    t.integer "sign_in_count",   default: 0,  null: false 
    t.datetime "current_sign_in_at" 
    t.datetime "last_sign_in_at" 
    t.string "current_sign_in_ip" 
    t.string "last_sign_in_ip" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    t.boolean "admin",     default: false 
    t.string "type" 
    t.string "first_name" 
    t.string "last_name" 
    end 

的routes.rb:

resources :materials 

    root 'static_pages#home' 

    devise_for :users, :controllers => { registrations: 'registrations' } 

    get 'admin' => 'static_pages#admin' 

    resources :groups 
    resources :users 
    resources :students 
    resources :teachers 
    resources :testimonials 
    post 'assign_to_group' => 'students#assign_to_group' # Could have been 'patch', but default in the controller method is 'post', so I left the method as default and changed this route to 'post'. Doesn't NEED to be patch. 
    post 'remove_from_group' => 'students#remove_from_group' 
    post 'unassign_teacher' => 'groups#unassign_teacher' 
    post 'assign_as_student' => 'teachers#assign_as_student' 
    post 'assign_as_teacher' => 'students#assign_as_teacher' 
    post 'add_student' => 'groups#add_student' 
    post 'remove_student_from_group' => 'groups#remove_student_from_group' 
+0

在你的天賦 - 嘗試檢查的東西,用戶實際會/不會在管理頁面上看到,例如'expect(page).not_to have_content(「Welcome Mr Admin」)'或者登錄管理頁面上實際存在的任何內容 - 如果你能看到,那麼是的,你需要弄清楚爲什麼人們會自動登錄到管理員。否則,它可能是他們在管理員登錄頁面? –

+0

此外,樣式點:使用'&&'和'||'而不是'和'和'或'(閱讀爲什麼在這裏:http://devblog.avdi.org/2010/08/02/using-and-and第二:'current_user.admin == true'這是非常危險的......如果你不小心忘記了其中一個'='會發生什麼 - 這是一個很難發現的錯誤,並且不會真正導致你的錯誤代碼失敗...只是默默地讓所有用戶看到管理頁面。總是這樣做是一個好習慣:'true == current_user.admin'如果不小心使用了'=',那麼這會失敗 –

回答

0

你的測試失敗的原因是您在重定向之前檢查current_path 已完成。基本上你打電話訪問(xxx),它將current_path設置爲xxx,然後立即讀回xxx,而服務器將重定向返回到/,然後瀏覽器將current_path更改爲/。只要你使用的水豚2.5+你應該使用have_current_path匹配,這將重試了一下,從而使重定向實時處理

expect(page).to have_current_path(root_path)