设计用户注册和登录。水豚和管理员用户权限(和设计)的问题
使用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'
在你的天赋 - 尝试检查的东西,用户实际会/不会在管理页面上看到,例如'expect(page).not_to have_content(“Welcome Mr Admin”)'或者登录管理页面上实际存在的任何内容 - 如果你能看到,那么是的,你需要弄清楚为什么人们会自动登录到管理员。否则,它可能是他们在管理员登录页面? –
此外,样式点:使用'&&'和'||'而不是'和'和'或'(阅读为什么在这里:http://devblog.avdi.org/2010/08/02/using-and-and第二:'current_user.admin == true'这是非常危险的......如果你不小心忘记了其中一个'='会发生什么 - 这是一个很难发现的错误,并且不会真正导致你的错误代码失败...只是默默地让所有用户看到管理页面。总是这样做是一个好习惯:'true == current_user.admin'如果不小心使用了'=',那么这会失败 –