我一直在阅读Railstutorial,并对第二次Chapter 10练习的“额外学分”感到好奇。搜索周围,我遇到了另一个StackOverflow Q&A。我遵循提问者提供的逻辑,所以我也很困惑他们为什么会失败。
我复制了原始提问者的工作&后续失败,但提供的唯一答案并不能解决问题 - 它实际上会产生错误(同样,domain_scope
在下一章之前不作为主题进行讨论。)
我会对问题或答案发表评论,但不幸的是,我也没有声誉 - 而且我不想滥用答案功能来分享这个“我也是!”。
对原始提问者充分尊重,这是有问题的代码(从原始问题复制)
def index
@users = User.where(activated: true).paginate(page: params[:page])
end
def show
@user = User.find(params[:id])
redirect_to root_url and return unless @user.activated?
end
test "only show profiles of activated users" do
log_in_as(@admin)
get users_path
assert_template 'users/index'
assert_select 'div.pagination'
first_page_of_users = User.paginate(page: 1)
first_page_of_users.each do |user|
assert_equal true, user.activated?
end
end
non:
name: Non Activated
email: nonactivated@example.gov
password_digest: <%= User.digest('password') %>
activated: false
FAIL["test_only_show_profiles_of_activated_users", UsersIndexTest, 2015-08-12 12:45:43 -0700]
test_only_show_profiles_of_activated_users#UsersIndexTest (1439408743.76s)
Expected: true
Actual: false
test/integration/users_index_test.rb:34:in `block (2 levels) in <class:UsersIndexTest>'
test/integration/users_index_test.rb:33:in `block in <class:UsersIndexTest>'
test "only show profiles of activated users" do
log_in_as(@admin)
get users_path
assert_template 'users/index'
assert_select 'div.pagination'
first_page_of_users = User.paginate(page: 1)
first_page_of_users.each do |user|
default_scope where(:published => true)
end
end
ERROR["test_only_show_profiles_of_activated_users", UsersIndexTest, 2015-08-12 12:45:44 -0700]
test_only_show_profiles_of_activated_users#UsersIndexTest (1439408744.71s)
NoMethodError: NoMethodError: undefined method `where' for #<UsersIndexTest:0x007faf7aa91d80>
test/integration/users_index_test.rb:34:in `block (2 levels) in <class:UsersIndexTest>'
test/integration/users_index_test.rb:33:in `block in <class:UsersIndexTest>'
test/integration/users_index_test.rb:34:in `block (2 levels) in <class:UsersIndexTest>'
test/integration/users_index_test.rb:33:in `block in <class:UsersIndexTest>'
我已经尝试了另一种集成测试,但也失败了:
def setup
@admin = users(:michael)
@non_admin = users(:foo)
@non_activated = users(:non)
end
test "only show profiles of activated users" do
log_in_as(@admin)
get users_path
assert_template 'users/index'
assert_select 'div.pagination'
first_page_of_users = User.paginate(page: 1)
first_page_of_users.each do |user|
assert_not user_path(@non_activated)
end
end
FAIL["test_only_show_profiles_of_activated_users", UsersIndexTest, 2015-08-12 12:45:43 -0700]
test_only_show_profiles_of_activated_users#UsersIndexTest (1439408743.72s)
Expected "/users/895943698" to be nil or false
test/integration/users_index_test.rb:35:in `block (2 levels) in <class:UsersIndexTest>'
test/integration/users_index_test.rb:34:in `block in <class:UsersIndexTest>’
这些失败似乎表明index
中users_controller.rb
操作的代码更改无法正常工作 - 但我已经通过手动测试确认它是。
最值得赞赏的任何帮助!
答案 0 :(得分:3)
我也在研究这个问题。我想我找到了你的问题。
在测试中,您使用代码
提取用户的第一页first_page_of_users = User.paginate(page: 1)
当您为非活动用户检查此项时,会出现错误,因为您的Users数据库中的某个条目处于非活动状态。你从来没有把它从你的阵列中删除。
我认为您可以通过使用此行来包含“where activated”条件来解决此问题。
first_page_of_users = User.where(activated: true).paginate(page: 1)
但是我不喜欢这个解决方案,因为它不像你在users_controller中编写的那样检查索引。
这是我的解决方案,我将其包含在我的“index as admin with pagination”test:
中User.paginate(page: 1).each do |user|
if user.activated?
assert_select 'a[href=?]', user_path(user), text: user.name
unless user == @admin
assert_select 'a[href=?]', user_path(user), text: 'delete'
end
else
assert_select 'a[href=?]', user_path(user), text: user.name, count: 0
end
end
以下是它的工作原理:它会拉出用户的第一页,如果用户被激活,它会查找指向用户的链接以及删除按钮。如果未激活用户,则会检查以确保未显示用户。
答案 1 :(得分:2)
我和Mickey基本上采用了相同的解决方案(并提出了他的解决方案),除了我使用了一个稍微不同的assert_select实现:
User.paginate(page: 1).each do |user|
if user.activated?
assert_select 'a[href=?]', user_path(user), text: user.name
unless user == @admin
assert_select 'a[href=?]', user_path(user), text: 'delete'
end
else
assert_select 'a[href=?]', user_path(user), false
end
end
我对assert_select的这种用法的理解是为了确保没有包含未激活用户的user_path的href的锚元素。这基本上与确保具有带有user_path的href的锚元素的数量为零(Mickey的解决方案)相同。测试套件喜欢这两个版本。
这和Mikey的答案适用于额外学分的第一部分,即针对/ users的写入集成测试。对于额外学分的第二部分,即写入集成测试对于 / users /:id ,我执行了以下操作:
首先我做了一个新的集成测试(见脚注为什么):
rails generate integration_test users_show
然后我更新了 app / controllers / users_controller.rb ,并在 test / fixtures / users.yml 中创建了一个未激活的用户。
应用/控制器/ users_controller.rb:强>
def show
@user = User.find(params[:id])
redirect_to root_url and return unless @user.activated?
end
<强>测试/装置/ users.yml里:强>
.
.
.
archer:
name: Sterling Archer
email: duchess@example.gov
password_digest: <%= User.digest('password') %>
activated: true
activated_at: <%= Time.zone.now %>
lana:
name: Lana Kane
email: hands@example.gov
password_digest: <%= User.digest('password') %>
activated: false
最后,我添加了@unactivated_user
和一个新测试,以自动生成 test / integration / users_show_test.rb :
require 'test_helper'
class UsersShowTest < ActionDispatch::IntegrationTest
def setup
@unactivated_user = users(:lana)
@activated_user = users(:archer)
end
test "should redirect to root_url when user not activated" do
log_in_as(@unactivated_user)
assert_redirected_to root_url
end
test "should not redirect root_url when user is activated" do
log_in_as(@activated_user)
assert_redirected_to @activated_user
end
end
执行此操作后,我的测试套件显示为绿色。我添加了@activated_user
和第二个测试,以确保第一次测试通过时不是侥幸(因为我在测试中真的很新)。
*脚注:首先我尝试将测试添加到 test / controllers / users_controller_test.rb ,但我很快就明白,虽然这可行,但它不符合它的标准<按照额外信用分配中的规定进行的em>集成测试,似乎需要额外的一步才能使其工作:
test "should redirect to root_url when user not activated" do
log_in_as(@unactivated_user)
get :show, id: @unactivated_user
assert_redirected_to root_url
end
在我意识到它可能应该是集成测试而不是控制器测试之后,我找到了一个现有的测试文件来放置它。因为users_edit_test,users_index_test,users_login_test和users_signup_test似乎不适合这个测试,所以我刚刚创建了一个新测试。好像很好。
答案 2 :(得分:0)
对不起安娜,但你得到了&#34;额外信用的第二部分&#34;错
任务是建立一个测试,确保登录用户无法看到未激活的用户
您编写测试的方式(第二次)是未激活的用户将尝试查看自己的个人资料页面 (这也会将他重定向到根网址,但这就是因为每个未激活的用户试图访问的页面都会将他重定向到root_url)
测试应该像那样
require 'test_helper'
class UsersShowTest < ActionDispatch::IntegrationTest
def setup
@unactivated_user = users(:moshe)
@activated_user = users(:archer)
end
test "should only show activated users" do
log_in_as (@activated_user)
get user_path(@unactivated_user)
assert_redirected_to root_url
end
end
答案 3 :(得分:0)
当我尝试将未激活的用户添加到users.yml fixture时,users_index_test.rb测试&#34;索引为admin,包括分页和删除链接&#34;会失败
失败[&#34; test_index_as_admin_including_pagination_and_delete_links&#34;,UsersIndexTest,1.7782473900006153] test_index_as_admin_including_pagination_and_delete_links #UsersIndexTest(1.78s) 预计至少有1个元素匹配&#34; a [href =&#34; / users / 659682706&#34;]&#34;,找到0 .. 预期0为&gt; = 1。 test / integration / users_index_test.rb:18:in
block (2 levels) in <class:UsersIndexTest>' test/integration/users_index_test.rb:17:in
块中&#39;
我首先尝试通过添加
简单地在该测试中包含激活用户的测试if user == @unactivated_user
assert_redirected_to root_url
else
<the original test code>
那产生了错误
失败[&#34; test_index_as_admin_including_pagination_and_delete_links&#34;,UsersIndexTest,1.7827676309971139] test_index_as_admin_including_pagination_and_delete_links #UsersIndexTest(1.78s) 预期的响应是&lt; 3XX:重定向&gt;,但是&lt; 200:OK&gt; test / integration / users_index_test.rb:19:在
block (2 levels) in <class:UsersIndexTest>' test/integration/users_index_test.rb:17:in
块中&#39;
所以我将if条件更改为true,并添加了一个以非管理员激活的用户身份登录的单独测试。这似乎有效。我的users_index_test.rb已完整:
require 'test_helper'
class UsersIndexTest < ActionDispatch::IntegrationTest
def setup
@admin = users(:michael)
@non_admin = users(:archer)
@unactivated_user = users(:malory)
end
test "index as admin including pagination and delete links" do
log_in_as(@admin)
get users_path
assert_template 'users/index'
assert_select 'div.pagination', count: 2
first_page_of_users = User.paginate(page: 1)
first_page_of_users.each do |user|
if user == @unactivated_user
true
else
assert_select 'a[href=?]', user_path(user), text: user.name
unless user == @admin
assert_select 'a[href=?]', user_path(user), text: 'delete'
end
end
end
assert_difference 'User.count', -1 do
delete user_path(@non_admin)
end
end
#
# User.paginate(page:1).each do |user|
# assert_select 'a[href=?]', user_path(user), text: user.name
# end
# end
test "index as non-admin" do
log_in_as(@non_admin)
get users_path
assert_select 'a', text: 'delete', count: 0
end
test "should only show activated users" do
log_in_as(@non_admin)
get user_path(@unactivated_user)
assert_redirected_to root_url
end
end
我的users.yml:
# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
#empty
michael:
name: Michael Example
email: michael@example.com
password_digest: <%= User.digest('password') %>
admin: true
activated: true
activated_at: <%= Time.zone.now %>
archer:
name: Sterlin Archer
email: duchess@example.gov
password_digest: <%= User.digest('password') %>
activated: true
activated_at: <%= Time.zone.now %>
lana:
name: Lana Kane
email: hands@example.gov
password_digest: <%= User.digest('password') %>
activated: true
activated_at: <%= Time.zone.now %>
malory:
name: Malory Archer
email: boss@example.gov
password_digest: <%= User.digest('password') %>
activated: false
#activated_at: <%= Time.zone.now %>
<% 30.times do |n| %>
user_<%= n %>:
name: <%= "User #{n}" %>
email: <%= "user-#{n}@example.com" %>
password_digest: <%= User.digest('password') %>
activated: true
activated_at: <%= Time.zone.now %>
<% end %>
我的users_controller.rb:
class UsersController < ApplicationController
before_action :logged_in_user, only: [:index, :edit, :update, :destroy]
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: :destroy
def index
@users = User.where(activated: true).paginate(page: params[:page])
end
def show
@user = User.find(params[:id])
redirect_to root_url and return unless @user.activated?
end
def new
@user = User.new
end
def create
@user = User.new(user_params)
if @user.save
@user.send_activation_email
flash[:info] = "Please check your email to activate your account."
redirect_to root_url
else
render 'new'
end
end
def edit
@user= User.find(params[:id])
end
def update
#@user = User.find(params[:id])
if @user.update_attributes(user_params)
#sign_in @user
flash[:success] = "Profile updated"
redirect_to @user
else
render 'edit'
end
end
def destroy
User.find(params[:id]).destroy
flash[:success] = "User deleted"
redirect_to users_path
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
# Before filters
# Confirms a logged-in user
def logged_in_user
unless logged_in?
store_location
flash[:danger] = "Please log in."
redirect_to login_url
end
end
# Confirms the correct user.
def correct_user
@user = User.find(params[:id])
redirect_to(root_url) unless current_user?(@user)
end
#Confirms an admin user
def admin_user
redirect_to(root_url) unless current_user.try(:admin?)
end
end
希望我的解决方案可以帮助某人。
答案 4 :(得分:0)
此集成测试也存在问题。 不要忘记在灯具中设置至少1个用户&#34;激活= false&#34; 我的简短解决方案,希望它可以帮到某人 的 users.yml里强>
purrr
仅检查&#34;未激活的用户未显示&#34;
<强> users_index_test.rb 强>
michael:
name: Michael Example
email: michael@example.com
password_digest: <%= User.digest('password') %>
admin: true
activated: true
activated_at: <%= Time.zone.now %>
archer:
name: Sterling Archer
email: duchess@example.gov
password_digest: <%= User.digest('password') %>
activated: false #do not forget to set at least 1 user activated to false
activated_at: <%= Time.zone.now %>
lana:
name: Lana Kane
email: hands@example.gov
password_digest: <%= User.digest('password') %>
activated: true
activated_at: <%= Time.zone.now %>
malory:
name: Malory Archer
email: boss@example.gov
password_digest: <%= User.digest('password') %>
activated: true
activated_at: <%= Time.zone.now %>
<% 30.times do |n| %>
user_<%= n %>:
name: <%= "User #{n}" %>
email: <%= "user-#{n}@example.com" %>
password_digest: <%= User.digest('password') %>
activated: true
activated_at: <%= Time.zone.now %>
<% end %>
请勿忘记更改 users_controller.rb 以确保测试正确性
class UsersIndexTest < ActionDispatch::IntegrationTest
def setup
@admin = users(:michael)
@non_admin = users(:lana)
end
test 'display only activated users' do
log_in_as(@non_admin)
get users_path
first_page_of_users = User.where(activated: false).paginate(page: 1)
first_page_of_users.each do |user|
assert_select 'a[href=?]', user_path(user), text: user.name, count: 0
end
end
end
这样你就可以检查测试是否正常工作
ADD 不会将最旧的测试索引作为管理员包括分页和删除链接 添加 where(activated = true),如下所示
def index
# @users = User.where(activated: true).paginate(page: params[:page])
@users = User.paginate(page: params[:page])
end