2012-03-31 27 views
6

Tôi là một người mới sử dụng Ruby và Rails, đó là lý do tại sao tôi sẽ trải qua Rails Tutorial bởi Michael Hartl. Tôi bị kẹt ở Chương 9, Bài tập # 9. Tôi đã cập nhật def phá hủy mã trong Controller Người sử dụng để:Bài hướng dẫn của Ruby Bài tập # 9 - Không cho phép quản trị tự xóa

def destroy 
    user = User.find(params[:id]) 
    if (current_user == user) && (current_user.admin?) 
    flash[:error] = "Can not delete own admin account!" 
    else 
    user.destroy 
    flash[:success] = "User destroyed." 
    end 
redirect_to users_path 
end 

Điều này dường như làm việc khi tôi thử nghiệm trong trình duyệt bằng cách thêm "xóa" liên kết đến CURRENT_USER khi admin đăng nhập Nhưng tập thể dục nói. để viết một bài kiểm tra đầu tiên - mà tôi đã làm nhưng dường như không hoạt động. Dưới đây là những gì tôi có cho thử nghiệm:

describe "as admin user" do 
    let(:user_admin) { FactoryGirl.create(:admin) } 

    before { sign_in user_admin } 

    describe "submitting a DELETE request to destroy own admin account" do 
    before { delete user_path(user_admin) } 
    it { should have_selector('div.alert.alert-error', text: 'delete own admin') } 
    end 
end 

Có lẽ những gì tôi đang thử nghiệm sẽ không được kiểm tra. Làm thế nào để bạn kiểm tra việc sửa đổi mã hủy diệt trong Bộ điều khiển người dùng?

+0

Tôi tin rằng bạn có thể có nghĩa là Chương 9 Bài tập 10 - ít nhất đó là những gì nó đang hiển thị như trong phiên bản trực tiếp tính đến hôm nay. – eblume

Trả lời

1

Tôi cũng mới với Hướng dẫn Rails (và Rails nói chung) và có cùng một vấn đề này, và câu hỏi của bạn đã giúp tôi tìm ra câu trả lời.

Tôi vẫn không chắc chắn tại sao mã của bạn không thành công, chính xác, nhưng các bước sau đây chắc chắn đã hiệu quả.

Thứ nhất, sửa đổi các mã kiểm tra hơi để sử dụng cấu trúc sau (ở đây tôi đã rời khỏi nơi để đặt mô tả khối này - bạn có đúng nơi đã được):

describe "deleting herself" do 
    it "should not be possible" do 
    expect { delete user_path(admin) }.to_not change(User, :count).by(-1) 
    end 
end 

Lưu ý rằng tôi đang sử dụng một mong đợi {} khối theo dõi số lượng đối tượng Người dùng. Điều này chắc chắn gây ra các thử nghiệm để đi Red (đó là tốt vào thời điểm này), trong khi kiểm tra cho Flash sẽ cũng làm cho thử nghiệm đi Red, nhưng kiểm tra cho đèn flash lỗi dường như không hoạt động ở đây. Tôi thực sự không biết tại sao! Có lẽ một cái gì đó để làm với chuyển hướng kép xảy ra?

Tiếp theo, viết mã bảo vệ để thực hiện lại các thử nghiệm. Mã của bạn làm việc (tôi nghĩ), nhưng tôi nghĩ rằng mã của tôi là thành ngữ hơn một chút ở chỗ nó sử dụng những người giúp đỡ phiên được xác định trước đó trong Chương 9.

def destroy 
    user = User.find(params[:id]) 
    if (current_user? user) && (current_user.admin?) 
    flash[:error] = "You are not allowed to delete yourself as an admin." 
    else 
    user.destroy 
    flash[:success] = "User destroyed. ID: #{user.id}" 
    end 
    redirect_to users_path 
end 

Sự thay đổi này làm cho thử nghiệm của tôi đi 'xanh' một lần nữa, mà hoàn tất thành công Bài tập 10.

3

Tôi đã cố gắng lấy mã trong bài gốc để làm việc, nhưng không có may mắn. Thay vào đó, tôi đã làm cho nó hoạt động như thế này (khiến nó thất bại, rồi vượt qua). Điều này kiểm tra cho chuyển hướng thích hợp cũng như thông điệp flash chính xác.

THE TEST: authentication_pages_spec.rb

describe "as admin user" do 
    let(:admin) { FactoryGirl.create(:admin) } 
    before { sign_in admin } 

    describe "can't delete self by submitting DELETE request to Users#destroy" do 
     before { delete user_path(admin) } 
     specify { response.should redirect_to(users_path), 
        flash[:error].should =~ /Can not delete own admin account!/i } 
    end 
    end 

THỰC HIỆN: Người dùng # phá hủy

def destroy 
    user = User.find(params[:id]) 
    if (current_user == user) && (current_user.admin?) 
     flash[:error] = "Can not delete own admin account!" 
    else 
     user.destroy 
     flash[:success] = "User destroyed." 
    end 
    redirect_to users_path 
    end 

Có lẽ lý do thử nghiệm ban đầu đã không làm việc là vì con đường chúng tôi đang phát hành theo yêu cầu? tôi đã cố gắng thêm mỗi trong các cách sau riêng vào khối mô tả và đều thất bại:

it { should have_selector('div.alert.alert-error', text: 'delete own admin') } 

it { should have_selector('title', text: 'All users') } 
it { should have_selector('h1', text: 'All users') } 

Vì vậy, có vẻ như Capybara là không thực sự chuyển hướng đến trang để kiểm tra các bộ chọn. Tôi đã thử 'tiêu đề' và 'h1', nghĩ rằng có thể có một số vấn đề với bộ chọn 'div.alert.alert-error' ... nhưng 'tiêu đề' và 'h1' không thành công với cùng "CSS dự kiến ​​sẽ trả về một cái gì đó" ...

Bất kỳ ai cũng biết thêm về cách kiểm tra kiểu specify { response.should ... } hoạt động như thế nào? Nếu họ không làm theo chuyển hướng khi họ nhấn hành động điều khiển?

0

Tôi cũng mới trong Rails, chỉ cần làm hướng dẫn lần đầu tiên, bài đăng của bạn giúp tôi rất nhiều nhưng chỉ để đóng góp, bạn không thực sự cần phải kiểm tra xem người dùng có phải là quản trị viên trong khi hủy phá hủy sẽ chỉ khả dụng cho người dùng quản trị khi thêm dòng

before_action :admin_user,  only: :destroy 

Trong bộ điều khiển người dùng.

Vì vậy, nó là đủ để chỉ cần hỏi nếu không phải là giống như người dùng hiện

def destroy 
    usertodestroy = User.find(params[:id]) 
    if (current_user == usertodestroy) 
    flash[:error] = 'Can´t delete own user' 
    else 
    usertodestroy.destroy 
    flash[:success] = "User destroyed. ID: #{usertodestroy.name}" 
    redirect_to users_url 
    end 
end 

Ngoài ra kiểm tra nên chỉ yêu cầu số lượng đã không thay đổi sau khi cố gắng xóa

describe "as admin user" do 
    let(:admin) { FactoryGirl.create(:admin) } 
    before { sign_in(admin) } 

    it "should not be able to delete itself" do 
    expect { delete user_path(admin) }.not_to change(User, :count) 
    end 
end 

Cả hai làm không thay đổi kết quả nhưng họ chỉ giữ cho mọi thứ đơn giản hơn.

Tại sao tôi có thể không thực sự nhận được là tại sao đoạn code tiếp theo là trong mọi trường hợp xóa người dùng khi kiểm tra:

describe "as admin user" do 
    let(:admin) { FactoryGirl.create(:admin) } 
    before { sign_in(admin) } 

    it "should not be able to delete itself" do 
    expect { admin.destroy }.not_to change(User, :count) 
    end 
end 

Theo tôi điều này được gọi thẳng các UsersController vì vậy không nên bị xóa.

+0

(Tôi là một Rails newb, nhưng đã làm Ruby cho một vài năm ...) Tôi nghĩ rằng phiên bản thứ hai được gọi là phương pháp tiêu diệt của đối tượng quản trị, không phải là phương pháp phá hủy của dụ UsersController, và đó là lý do tại sao (admin) người dùng bị phá hủy bất kể mã trong tệp điều khiển của bạn. – davej

0

Mặc dù sau những gợi ý trên thử nghiệm của tôi là vẫn không trôi qua, với các lỗi:

undefined method `admin?' for nil:NilClass 

Mà tôi đã xuống có nghĩa là có một số vấn đề với đăng nhập vào vì đây là chỉ gọi là một phần của before_filter 'admin_user' kiểm tra.

tôi đã có thể giải quyết điều này bằng cách sử dụng phiên bản phi Capybara của dấu hiệu trong phương pháp

before { signin admin, no_capybara: true } 

Cảm ơn!

0

tôi áp dụng eblume gợi ý cho tốt, tôi có một số nhận xét và nghi ngờ mặc dù:

Thứ nhất, kiểm tra có thể được đơn giản hóa như chúng ta không cần phải kiểm tra xem những thay đổi đếm bởi một đơn vị nhưng nếu nó thay đổi theo số bất kỳ:

expect { delete user_path(admin) }.not_to change(User, :count) 

Về mã trong bộ điều khiển, nó cũng có thể được đơn giản hóa. Vì chúng tôi đã mã hóa các mục sau đây trước khi hành động hủy:

def admin_user 
    redirect_to(root_url) unless current_user.admin? 
end 

không cần phải kiểm tra trong phương thức 'hủy' nếu người dùng là quản trị viên, nó phải là quản trị viên.

Vì vậy mệnh đề nếu trở thành:

if (current_user? user) 

Vấn đề của tôi bây giờ là: Tôi không hiểu mã này, tôi không biết những gì kiểm tra điều này.

thử đầu tiên của tôi đã sử dụng lệnh sau:

if (current_user.id == params[:id]) 

Nhưng điều này không làm việc, tôi không hiểu tại sao.

1

Cũng đáng để chỉ ra rằng trong danh sách tutorial trong danh sách 9.43 chế độ xem một phần trong ứng dụng/lượt xem/người dùng/_user.html.erb có một dấu kiểm để ngăn hiển thị liên kết 'xóa' cho người dùng quản trị viên đã đăng nhập hiện tại trên trang chỉ mục người dùng. Vì vậy, mặc dù người dùng không thể xóa tài khoản của mình thông qua giao diện người dùng web, tôi đoán bài tập 9.9 cũng đi xa hơn, đảm bảo có logic ở cấp bộ điều khiển trong trường hợp ai đó tạo và gửi yêu cầu xóa http cho người dùng hiện tại.

Có thể là một thực hành tốt để bổ sung các nhân viên bảo vệ an toàn này vào các ứng dụng đường ray của bạn để ngăn chặn bất kỳ lỗi lạ nào xén.

Vì bộ lọc ở chế độ xem từng phần làm cho nó trở nên bạn không bao giờ thấy đèn flash lỗi, bạn cũng có thể đơn giản hóa hành động tiêu diệt của Bộ điều khiển người dùng bằng cách xóa 'else'.

def destroy 
    user = User.find(params[:id]) 
    unless current_user?(user) 
    user.destroy 
    flash[:success] = "User deleted." 
    end 
    redirect_to users_url 
end 
+0

Đặt tốt. Theo như tôi có thể nói nó sẽ là phi logic để có một thông báo flash cho thấy "Bạn không thể xyz" sau một dòng mà ngăn chặn 'xyz' từ bao giờ xảy ra. – LpLrich

0

hành động điều khiển

def destroy 
    usertodestroy = User.find(params[:id]) 
    if (current_user == usertodestroy) 
    flash[:error] = 'Can´t delete own user' 
    redirect_to root_url 
    else 
    usertodestroy.destroy 
    flash[:success] = "User destroyed. ID: #{usertodestroy.name}" 
    redirect_to users_url 
    end 
end 

và thử nghiệm

describe "as admin user" do 
    let(:admin) { FactoryGirl.create(:admin) } 
    before { sign_in admin, no_capybara: true } 

    it "attempting to delete self" do 
    expect{ delete user_path(admin) }.not_to change(User, :count) 
    end 
end 

làm việc cho tôi.

+1

Bạn có thể giải thích những gì bạn đã thay đổi và tại sao nó hoạt động không? – Chris

+0

Tôi chỉ so sánh người dùng đăng nhập và người dùng hiện tại. Nếu nó là cùng một người, sau đó ông không thể xóa chính mình và chuyển hướng anh ta đến root_url. Nếu không - thì người dùng hiện tại có thể xóa bất kỳ ai nếu có admin: true property. Và chúng tôi kiểm tra điều này (admin không thể tự xóa) trong thử nghiệm. – xAgrh

Các vấn đề liên quan