10.4 destroying users
in this chapter, we will add destroy action to users controller to finish REST.
first, we need to add administrative users who can use the destroy action. so we need to add a new attr of admin which is a boolean.
and in the model, you can use admin? to get this attr value.
1. let's write the unit test first.:
describe "admin attribute" do before(:each) do @user = User.create!(@attr) end it "should respond to admin" do @user.should respond_to(:admin) end it "should not be an admin by default" do @user.should_not be_admin end it "should be convertible to an admin" do @user.toggle!(:admin) @user.should be_admin end end end
note, we use
@user.toggle!(:admin)
rails can detect the boolean attr, and auto add a new question mark method of admin?
2. next, let's add a new attr to users table.
rails g migration add_admin_to_users admin:boolean
this wiil add a new column, and the default value is nil.
so to be clear, you can change the migration file:
add_column :users, :admin, :boolean, :default => false
3. next, we need to migrate to database, and also do test:prepare to update test database.
rake db:migrate rake db:test:prepare
4. revisiting attr_accessible
you may wondering, why we use toggle!, instead of assign ":admin=>true" directly?
because this will not work, as we defined attr_accessible, and :admin is not in the list.
so you can't do mass assignment for admin column.
explicily define attr_accessible is crucial for a good site security. if you omit it, any user can issue such request:
put /users/17?admin=1
then this user can do everything bad.
so define attr_accessible for every model is a good practice.
5. adding destroy action:
first, let's add delete link to the user's list page:
<li> <%= gravatar_for user, :size => 30 %> <%= link_to user.name, user %> <% if current_user.admin? %> | <%= link_to "delete", user, :method => :delete, :confirm => "You sure?", :title => "Delete #{user.name}" %> <% end %> </li>
note:
the method is ":delete", so this link will issue a DELETE request.
Web browsers can't send DELETE link natively, so rails fakes with javascript.
But to get this delete link to work, we have to include rails default javascript library, :defaults.
<%= javascript_include_tag :defaults %>
this line code is in app/views/layouts/application.html.erb
def destroy User.find_by_id(params[:id]).destroy flash[:success] = "User destroied." redirect_to users_path end
note:
User.find_by_id(params[:id]).destroy