sample_app/Gemfile
# faker for creating sample users for testing
gem 'faker', '1.7.3'
* Then I ran bundle install.
$ bundle install
Bundle complete! 19 Gemfile dependencies, 67 gems now installed.
Gems in the group production were not installed.
Use `bundle show [gemname]` to see where a bundled gem is installed.
$ bundle show faker
/home/jimmyc/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/faker-1.7.3
* I added a Ruby program to seed the database.
sample_app/db/seeds.rb
User.create!(name: "Example User",
email: "example@railstutorial.org",
password: "foobar",
password_confirmation: "foobar")
99.times do |n|
name = Faker::Name.name
email = "example-#{n+1}@railstutorial.org"
password = "password"
User.create!(name: name,
email: email,
password: password,
password_confirmation: password)
end
* Next, I reset the database and then invoked the Rake task using db:seed
$ rails db:migrate:reset
$ rails db:seed
* I viewed the sample 100 users in the database. In Firefox, I type http://localhost:3000/users
* To limit only 30 users in a list user page, I added 'will_paginate' and 'bootstrap-will_paginate' Gems.
sample_app/Gemfile
# For pagination
gem 'will_paginate', '3.1.5'
gem 'bootstrap-will_paginate', '1.0.0'
* Then, I ran bundle install.
$ bundle install
$ bundle show will_paginate
/home/jimmyc/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/will_paginate-3.1.5
$ bundle show bootstrap-will_paginate
/home/jimmyc/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/bootstrap-will_paginate-1.0.0
* I editted the User List View index.html.erb file to make it supports will_paginate
sample_app/app/views/users/index.html.erb
<% provide(:title, 'All users') %>
<h1>All users</h1>
<%= will_paginate %>
<ul class="users">
<% @users.each do |user| %>
<li>
<%= gravatar_for user, size: 50 %>
<%= link_to user.name, user %>
</li>
<% end %>
</ul>
<%= will_paginate %>
* I re-wrote the index action of Users Controller to make it supports paginate function.
sample_app/app/controllers/users_controller.rb
def index
@users = User.paginate(page: params[:page])
end
* Then, I restarted the Rails Server.
Keyboard: Ctrl + C
Rendered /home/jimmyc/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/actionpack-5.0.2/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (1.2ms)
Rendered /home/jimmyc/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/actionpack-5.0.2/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout (29.1ms)
^C[3082] - Gracefully shutting down workers...
[3082] === puma shutdown: 2017-07-15 16:49:33 -0700 ===
[3082] - Goodbye!
Exiting
jimmyc@Jimmy-C-2017:~/sample_app$
$ rails s -b 0.0.0.0 -p 3000
* In Firefox, I type http://localhost:3000/. Then, "Users" menu on the top right corner.
* Now, this is important. I had to test whether the pagination works properly. The test included to visit the index path, verify the first page of users is present, and then confirm that pagination is present on the page.
* I created a list of fixtures of 34 users for testing.
sample_app/test/fixtures/users.yml
michael:
name: Michael Example
email: michael@example.com
password_digest: <%= User.digest('password') %>
archer:
name: Sterling Archer
email: duchess@example.gov
password_digest: <%= User.digest('password') %>
lana:
name: Lana Kane
email: hands@example.gov
password_digest: <%= User.digest('password') %>
malory:
name: Malory Archer
email: boss@example.gov
password_digest: <%= User.digest('password') %>
<% 30.times do |n| %>
user_<%= n %>:
name: <%= "User #{n}" %>
email: <%= "user-#{n}@example.com" %>
password_digest: <%= User.digest('password') %>
<% end %>
* I generated an Integration Test to test User Index.
$ rails generate integration_test users_index
Running via Spring preloader in process 6254
invoke test_unit
create test/integration/users_index_test.rb
* I copied and pasted the codes for the User Index Integration Test Suite to verify that all User Index links are working properly.
sample_app/test/integration/users_index_test.rb
require 'test_helper'
class UsersIndexTest < ActionDispatch::IntegrationTest
def setup
@user = users(:michael)
end
test "index including pagination" do
log_in_as(@user)
get users_path
assert_template 'users/index'
assert_select 'div.pagination', count: 2
User.paginate(page: 1).each do |user|
assert_select 'a[href=?]', user_path(user), text: user.name
end
end
end
* And then, I re-factored the User part of the User Index View.
sample_app/app/views/users/index.html.erb
<% provide(:title, 'All users') %>
<h1>All users</h1>
<%= will_paginate %>
<ul class="users">
<% @users.each do |user| %>
<%= render user %>
<% end %>
</ul>
<%= will_paginate %>
* I created a partial html.erb file _user.html.erb to display a single user in the user list.
sample_app/app/views/users/_user.html.erb
<li>
<%= gravatar_for user, size: 50 %>
<%= link_to user.name, user %>
</li>
* Then, I simplied the codes in User Index
sample_app/app/views/users/index.html.erb
<% provide(:title, 'All users') %>
<h1>All users</h1>
<%= will_paginate %>
<ul class="users">
<%= render @users %>
</ul>
<%= will_paginate %>
* After the ability of list users, I prepared to add the delete action for administrative user.
* First, I added the admin datafield attribute in the database metadata.
$ rails generate migration add_admin_to_users admin:boolean
* In the DB migration file, I added the default: false parameter to the admin field. That means a default new user added will be normal user, NOT admin user.
sample_app/db/migrate/20170716002656_add_admin_to_users.rb
class AddAdminToUsers < ActiveRecord::Migration[5.0]
def change
add_column :users, :admin, :boolean, default: false
end
end
* Then, I ran DB migrate command.
$ rails db:migrate
* After DB migration, I editted the seed file to make the first user is the admin user.
sample_app/db/seeds.rb
User.create!(name: "Example User",
email: "example@railstutorial.org",
password: "foobar",
password_confirmation: "foobar",
admin: true)
* And then, I reset the database.
$ rails db:migrate:reset
$ rails db:seed
* I added a test case "should not allow the admin attribute to be edited via the web" in the User Controller Test Suite.
sample_app/test/controllers/users_controller_test.rb
test "should not allow the admin attribute to be edited via the web" do
log_in_as(@other_user)
assert_not @other_user.admin?
patch user_path(@other_user), params: {
user: { password: "password",
password_confirmation: "password",
admin: true } }
assert_not @other_user.admin?
end
* In the _user.html.erb User Listing Partial file, I added a link to access the Delete User method that is granted to administrative privilege user.
sample_app/app/views/users/_user.html.erb
<li>
<%= gravatar_for user, size: 50 %>
<%= link_to user.name, user %>
<% if current_user.admin? && !current_user?(user) %>
| <%= link_to "delete", user, method: :delete,
data: { confirm: "You sure?" } %>
<% end %>
</li>
* In user controller, I added a destroy method in the logged_in_user before_action. In other words, a logged_in used can delete a record. And I added the def destroy method as well.
sample_app/app/controllers/users_controller.rb
before_action :logged_in_user, only: [:index, :edit, :update, :destroy]
def destroy
User.find(params[:id]).destroy
flash[:success] = "User deleted"
redirect_to users_url
end
* I added one more line to allow only admin_user can do the destroy action. And I added the private def admin_user method for the confirmation of admin user.
sample_app/app/controllers/users_controller.rb
before_action :admin_user, only: :destroy
# Confirms an admin user.
def admin_user
redirect_to(root_url) unless current_user.admin?
end
- Afterward, I tried to log in as admin user and deleted some users.
- In Firefox, I typed: http://localhost:3000/
- On the top right corner, I clicked Log in.
- I input the Example User with admin privillege:
- email: example@railstutorial.org
- password: foobar
- Then, I clicked the Log in button.
- After log in, Ruby on Rails brought me to the Profile screen of the Admin user.
- Then, I click User on the top menu.
- Firefox URL showed http://localhost:3000/users. Then I saw all users had the delete link except for Example User (self).
- I tried to delete the first user Titus Goldner. I clicked the delete button next to the name.
- A message box You sure? with Cancel and OK buttons, popped up.
- I clicked the OK button.
- Titus Goldner was deleted. A "User deleted" Flash message appeared on the top.
- I clicked the delete button for Flossie Macejkovic.
- Then, I clicked cancel.
- Flossie Macejkovic was still there.
- I clicked the delete button for Ignatius Abernathy.
- Then, I clicked OK.
- Ignatius Abernathy is deleted. A "User deleted" Flash message appeared on the top.
* As I checked on the server log of Ruby on Rails server. When I am deleting a user, the following log message will show out.
Started DELETE "/users/5" for 127.0.0.1 at 2017-07-15 18:09:50 -0700
Processing by UsersController#destroy as HTML
Parameters: {"authenticity_token"=>"v7doHoMVu55AZVNgwM3+SZvb2LVugO2yzqGDMl7hSYMmStu5LqFNmMiLhOLqmUT61q8T4k+IM7F0JhhAeZSTOQ==", "id"=>"5"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 5], ["LIMIT", 1]]
(0.1ms) begin transaction
SQL (0.4ms) DELETE FROM "users" WHERE "users"."id" = ? [["id", 5]]
(92.0ms) commit transaction
Redirected to http://localhost:3000/users
Completed 302 Found in 98ms (ActiveRecord: 92.8ms)
* For the testing suite of the admin privilege. I added the admin attribute for fictional test user Michael in the Test Fixtures.
sample_app/test/fixtures/users.yml
michael:
name: Michael Example
email: michael@example.com
password_digest: <%= User.digest('password') %>
admin: true
* I added two test cases: "should redirect destroy when not logged in" and "should redirect destroy when logged in as a non-admin" in the Users Controller Test Suite.
sample_app/test/controllers/users_controller_test.rb
test "should redirect destroy when not logged in" do
assert_no_difference 'User.count' do
delete user_path(@user)
end
assert_redirected_to login_url
end
test "should redirect destroy when logged in as a non-admin" do
log_in_as(@other_user)
assert_no_difference 'User.count' do
delete user_path(@user)
end
assert_redirected_to root_url
end
* On the other hand, I added two test cases "index as admin including pagination and delete links" and "index as non-admin" for User Index Integration Test.
sample_app/test/integration/users_index_test.rb
require 'test_helper'
class UsersIndexTest < ActionDispatch::IntegrationTest
def setup
@admin = users(:michael)
@non_admin = users(:archer)
end
test "index including pagination" do
log_in_as(@non_admin)
get users_path
assert_template 'users/index'
assert_select 'div.pagination', count: 2
User.paginate(page: 1).each do |user|
assert_select 'a[href=?]', user_path(user), text: user.name
end
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'
first_page_of_users = User.paginate(page: 1)
first_page_of_users.each do |user|
assert_select 'a[href=?]', user_path(user), text: user.name
unless user == @admin
assert_select 'a[href=?]', user_path(user), text: 'delete'
end
end
assert_difference 'User.count', -1 do
delete user_path(@non_admin)
end
end
test "index as non-admin" do
log_in_as(@non_admin)
get users_path
assert_select 'a', text: 'delete', count: 0
end
end
* Chapter 10 was a bit longer than others. To wrap up, I added all untracked files, committed the changes, merged to Master branch and pushed it onto Github. Then, I could call it a day.
$ git add -A
$ git commit -m "Finish user edit, update, index, and destroy actions"
$ git checkout master
$ git merge updating-users
$ git push
* The Github address for Michael Hartl's sample_app is https://github.com/jimmy2046/sample_app.
awesome post presented by you..your writing style is fabulous and keep update with your blogs Ruby on Rails Online Course India
ReplyDelete