$ rails _3.2.13_ new user_profile -d mysql
$ cd user_profile
Part 2: Devise Users
In /Gemfile,
gem 'devise'
$ bundle install
$ rails generate devise:install
In /config/environment/development.rb,
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
In /config/routes.rb,
root :to => "home#index"
In /app/views/layours/application.html.erb,
<body> <p class="notice"><%= notice %></p> <p class="alert"><%= alert %></p> <%= yield %>
In /config/application.rb,
# Enable the asset pipeline config.assets.enabled = true config.assets.initialize_on_precompile = false
$ rm public/index.html
Part 3: User Model
$ rails generate devise user
$ rake db:migrate
Part 4: Home Index Page
$ rails g controller home
In /app/controllers/home_controller.rb,
class HomeController < ApplicationController
def index
end
end
Create your own index page at /app/views/home/index.html.erb.
Part 5: Sign In, Sign Out and Register Links
Create the new file on /app/views/common/_session.html.erb and include the code below into the file:
<%- if user_signed_in? %>
<p>Hello <%= current_user.email %><br />
<%= link_to 'Sign out', destroy_user_session_path, :method => :delete %></p>
<%- else %>
<p>
<%= link_to 'Register', new_user_registration_path %> |
<%= link_to 'Sign in', new_user_session_path %>
</p>
<%- end %>
In /app/views/home/index.html.erb,
<div id="secondaryContent">
<%= render 'common/session' %>
</div>
$ rails g devise:views
Part 6: Authorization
In /app/controllers/application_controller.rb,
class ApplicationController < ActionController::Base
protect_from_forgery
protected
def authorize_user!
if user_signed_in?
return
else
flash[:notice] = 'You need to sign in first'
redirect_to new_user_session_path
end
end
end
In /app/controllers/home_controller.rb,
class HomeController < ApplicationController
before_filter :authorize_user!
def index
end
end
Part 7: Username
$ rails g migration add_username_to_users username:string
$ rake db:migrate
Add the code below into the 3 files as belows:
- /app/views/devise/registrations/edit.html.erb
- /app/views/devise/registrations/new.html.erb
- /app/views/devise/sessions/new.html.erb
<div><%= f.label :username %><br /> <%= f.text_field :username %></div>
In /config/initializers/devise.rb,
# ==> Configuration for any authentication mechanism # Configure which keys are used when authenticating a user. The default is # just :email. You can configure it to use [:username, :subdomain], so for # authenticating a user, both parameters are required. Remember that those # parameters are used only when authenticating and not when retrieving from # session. If you need permissions, you should implement that in a before filter. # You can also supply a hash where the value is a boolean determining whether # or not authentication should be aborted when the value is not present. config.authentication_keys = [ :username ]
In /app/models/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
# Setup accessible (or protected) attributes for your model
attr_accessible :username, :email, :password, :password_confirmation, :remember_me
end
Part 8: Name & Nickname
$ rails g migration add_name_to_users name:string
$ rails g migration add_nickname_to_users nickname:string
$ rake db:migrate
Add the code below into the 2 files as belows:
- /app/views/devise/registrations/edit.html.erb
- /app/views/devise/registrations/new.html.erb
<div><%= f.label :name %><br /> <%= f.text_field :name %></div> <div><%= f.label :nickname %><br /> <%= f.text_field :nickname %></div>
In /app/models/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
# Setup accessible (or protected) attributes for your model
attr_accessible :username, :email, :password, :password_confirmation, :name, :nickname, :remember_me
end
In /app/common/_session.html.erb,
<%- if user_signed_in? %>
<p>Welcome, <%= current_user.nickname %>!<br />
<%= link_to 'Sign out', destroy_user_session_path, :method => :delete %></p>
<%- else %>
<p>
<%= link_to 'Register', new_user_registration_path %> |
<%= link_to 'Sign in', new_user_session_path %>
</p>
<%- end %>
Part 9: Carrierwave File Uploads
In /Gemfile,
gem 'carrierwave'
$ bundle install
$ rails g uploader photo
$ rails g migration add_photo_to_users photo:string
$ rake db:migrate
In /app/models/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
# Setup accessible (or protected) attributes for your model
attr_accessible :username, :email, :password, :password_confirmation, :name, :nickname, :photo, :remote_photo_url, :remember_me
mount_uploader :photo, PhotoUploader
end
In /app/uploaders/photo_uploader.rb,
class PhotoUploader < CarrierWave::Uploader::Base
def extension_white_list
%w(jpg jpeg gif png)
end
end
Add the code below into the 2 files as belows:
- /app/views/devise/registrations/edit.html.erb
- /app/views/devise/registrations/new.html.erb
<div><%= f.label :photo %><br /> <%= f.file_field :photo %><br /> <%= f.label :remote_photo_url, "or photo URL" %> <%= f.text_field :remote_photo_url %> </div>
Part 10: User Authorization with Rolify and Cancan
In /Gemfile,
gem 'rolify' gem 'cancan'
$ bundle install
$ rails g rolify Role User
$ rake db:migrate
In /app/models/user.rb,
class User < ActiveRecord::Base
rolify
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :username, :email, :password, :password_confirmation, :name, :nickname, :photo, :remote_photo_url, :remember_me
attr_accessor :current_role
mount_uploader :photo, PhotoUploader
end
In /app/models/role.rb,
class Role < ActiveRecord::Base has_and_belongs_to_many :users, :join_table => :users_roles belongs_to :resource, :polymorphic => true scopify attr_accessible :name end
$ rails g cancan:ability
In /app/models/ability.rb,
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
if user.role? :admin
can :manage, :all
else
cannot :create, User
can :read, User
can :update, User
cannot :destroy, User
cannot :index, User
end
end
end
Part 11: User with Roles
Add the code below into the 2 files as belows:
- /app/views/devise/registrations/edit.html.erb
- /app/views/devise/registrations/new.html.erb
<div><%= f.label :role %><br />
<% for role in Role.find(:all) %>
<%= check_box_tag "user[role_ids][]", role.id, @user.roles.include?(role) %>
<%= role.name %><br/>
<% end %></div>
In /app/models/user.rb,
class User < ActiveRecord::Base
rolify
has_and_belongs_to_many :roles, :join_table => :users_roles
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :username, :email, :password, :password_confirmation, :name, :nickname, :photo, :remote_photo_url, :role_ids, :remember_me
attr_accessor :current_role
mount_uploader :photo, PhotoUploader
def role?(role_sym)
roles.any? { |r| r.name.underscore.to_sym == role_sym }
end
end
Part 12: User Management via CRUD
In order to manage our users through a CRUD interface we have to create a users controller and its associated views. First use rails to generate the users controller.
$ rails g controller users
In our users controller we are going to define the seven basic actions to maintain the RESTful protocol, so open up app/controllers/users_controller.rb and make it look like the following:
class UsersController < ApplicationController
before_filter :authorize_user!
load_and_authorize_resource
def index
@users = User.all
end
def show
@user = User.find(params[:id])
end
def new
@user = User.new
end
def edit
@user = User.find(params[:id])
end
def create
@user = User.new(params[:user])
if @user.save
redirect_to @user, :flash => { :success => 'User was successfully created.' }
else
render :action => 'new'
end
end
def update
@user = User.find(params[:id])
if @user.update_attributes(params[:user])
sign_in(@user, :bypass => true) if @user == current_user
redirect_to @user, :flash => { :success => 'User was successfully updated.' }
else
render :action => 'edit'
end
end
def destroy
@user = User.find(params[:id])
@user.destroy
redirect_to users_path, :flash => { :success => 'User was successfully deleted.' }
end
end
Now we need to create the associated views and a form partial.
$ cd app/views/users && touch _form.html.erb edit.html.erb index.html.erb new.html.erb show.html.erb
Make each of these files look as follows respectively:
In /app/views/users/_form.html.erb,
<%= form_for @user do |f| %>
<% if @user.errors.any? %>
<div class="error_explanation">
<h2><%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% @user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :username %>
<div class="controls">
<%= f.text_field :username %>
</div>
</div>
<div class="field">
<%= f.label :email %>
<div class="controls">
<%= f.email_field :email %>
</div>
</div>
<div class="field">
<%= f.label :password, "Password" %>
<div class="controls">
<%= f.password_field :password %>
</div>
</div>
<div class="field">
<%= f.label :password_confirmation %>
<div class="controls">
<%= f.password_field :password_confirmation %>
</div>
</div>
<div class="field">
<%= f.label :name %>
<div class="controls">
<%= f.text_field :name %>
</div>
</div>
<div class="field">
<%= f.label :nickname %>
<div class="controls">
<%= f.text_field :nickname %>
</div>
</div>
<div class="field">
<%= f.label :photo %>
<div class="controls">
<%= f.file_field :photo %>
</div>
<%= f.label :remote_photo_url, "or photo URL" %>
<%= f.text_field :remote_photo_url %>
</div>
<% if can? :create, @user %>
<div class="field">
<%= f.label :role %>
<div class="controls">
<% for role in Role.find(:all) %>
<%= check_box_tag "user[role_ids][]", role.id, @user.roles.include?(role) %>
<%= role.name %><br/>
<% end %>
</div>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
In /app/views/users/edit.html.erb,
<h1>Edit User</h1> <%= render 'form' %> <%= link_to 'Show User', @user %> <% if can? :index, @user %> | <%= link_to 'All Users', users_path %> <% end %>
In /app/views/users/index.html.erb,
<h1>Users</h1>
<table>
<thead>
<tr>
<th>Username</th>
<th>Email</th>
<th>Name</th>
<th>Nickname</th>
<th>Role</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% @users.each do |user| %>
<tr>
<td><%= user.username %></td>
<td><%= user.email %></td>
<td><%= user.name %></td>
<td><%= user.nickname %></td>
<td><%= user.roles.map(&:name).join(", ") %></td>
<td>
<%= link_to 'Show', user %>
<%= link_to 'Edit', edit_user_path(user) %>
<%= link_to 'Delete', user_path(user), :method => 'delete', :confirm => 'Are you sure?' %>
</td>
</tr>
<% end %>
</tbody>
</table>
<%= link_to 'New User', new_user_path %>
In /app/views/users/new.html.erb,
<h1>New User</h1> <%= render 'form' %> <%= link_to 'All Users', users_path %>
In /app/views/users/show.html.erb,
<h1>User</h1>
<p><strong>Username:</strong> <%= @user.username %></p>
<p><strong>Email:</strong> <%= @user.email %></p>
<p><strong>Name:</strong> <%= @user.name %></p>
<p><strong>Nickname:</strong> <%= @user.nickname %></p>
<p><strong>Photo:<strong><br />
<%= image_tag @user.photo_url %>
</p>
<p><strong>Role:</strong> <%= @user.roles.map(&:name).join(", ") %></p>
<% if can? :index, @user %>
<%= link_to 'All Users', users_path %> |
<% end %>
<%= link_to 'Edit User', edit_user_path(@user) %>
<% if can? :destroy, @user %>
| <%= link_to 'Delete User', user_path(@user), :method => 'delete', :confirm => 'Are you sure?' %>
<% end %>
Next we need to set up some routes so that the routes for devise and our users controller don't have any conflicts. So, open up config/routes.rb and make it look as follows:
Userapp::Application.routes.draw do
resources :users
devise_for :users, :skip => [:registrations, :sessions]
as :user do
get "/login" => "devise/sessions#new", :as => :new_user_session
post "/login" => "devise/sessions#create", :as => :user_session
delete "/logout" => "devise/sessions#destroy", :as => :destroy_user_session
end
root :to => 'users#index'
end
This routes.rb file first defines the RESTful routes for our users controller then tells devise to generate routes for users but to skip registrations and sessions. We skip the sessions routes because we will have to define them in a custom fashion so that they will not conflict with our RESTful users routes.
In /app/views/common/_session.html.erb,
<%- if user_signed_in? %>
<p>Welcome, <%= current_user.nickname %>!<br />
<%= link_to 'Sign out', destroy_user_session_path, :method => :delete %></p>
<%- else %>
<p>
<%= link_to 'Sign in', new_user_session_path %>
</p>
<%- end %>
In /app/controllers/application_controller.rb,
class ApplicationController < ActionController::Base
protect_from_forgery
def after_sign_in_path_for(resource)
user_path(current_user) #your path
end
protected
def authorize_user!
if user_signed_in?
return
else
flash[:notice] = 'You need to sign in first'
redirect_to new_user_session_path
end
end
end
In /app/views/devise/shared/_links.erb,
<%- if controller_name != 'sessions' %> <%#= link_to "Sign in", new_session_path(resource_name) %><!--<br />--> <% end -%> <%- if devise_mapping.registerable? && controller_name != 'registrations' %> <%#= link_to "Sign up", new_registration_path(resource_name) %><!--<br />--> <% end -%>
Now lets launch the application.
$ rails s
Navigate to http://localhost:3000/users/new in a web browser. Here we can create the first user of our application. Go ahead and create a user with an email address and password of your choice. Now go to http://localhost:3000 and click on the Log In link we made earlier. This brings us to the sign in page generated by devise but uses our custom /login route we specified in config/routes.rb. Authenticate with the account you just created. You should be greeted by the home page of the application with a success flash message and now a Log Out link. Congratulations! You can now create users and authenticate with devise. You can view a list of all the users by going to http://localhost:3000/users and from there you can edit or delete them.
Return to Internship Note (LoanStreet)
Previous Episode: User Authorization with Rolify and Cancan
Next Episode: Testing with RSpec
0 comments:
Post a Comment