In this post, I’m going to walkthrough how to quickly get up and running with Authlogic on Rails 3. This guide is setup so that at the end of each step you will have working software. When you’re finished, you will have a basic application that can authenticate users. Let’s get started!
To follow along in this example, you’ll want to make sure that you have the following installed:
Ruby 1.9.3
Rails 3.2.3
Bundler 1.1.0
The first thing we’re going to do is generate a new Rails application. Open your terminal and run the command below in the directory of your choice.
rails new authlogic_example
Next, let’s configure our new project to use the Authlogic gem. In your text editor, open the Gemfile
add the line below.
gem 'authlogic'
Finally, let’s install the gem using Bundler. In your terminal, run the command below.
bundle install
Let’s test our changes. In your terminal run the rails server command. Then, open you browser and navigate to http://localhost:3000
. If the application is configured properly you should see the Rails welcome page.
Our application will use two models: User
and UserSession
. The User
model will be responsible for persisting users in the database and the UserSession
model will be responsible for authenticating users and managing their sessions.
To generate these models, run the commands below in your terminal.
rails generate model User
rails generate authlogic:session UserSession
Several files should have been created. For now we’re only interested in the CreateUsers
migration that was created in the db/migrate
folder. We’re going to add some columns that Authlogic will recognize and use to authenticate our users.
In your text editor, modify the CreateUsers
migration to match the example below.
# db/migrate/*_create_users.rb
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :email, null: false
t.string :crypted_password, null: false
t.string :password_salt, null: false
t.string :persistence_token, null: false
t.timestamps
end
end
Now let’s configure the User model. We’ll add the acts_as_authlogic
macro to let Authlogic know that this is the model we’ll be authenticating with. We’ll also use attr_accessible
to make the email
, password
, and password_confirmation
attributes accessible to our controllers.
In your text editor, modify the User
model to match the example below.
# app/models/user.rb
class User < ActiveRecord::Base
acts_as_authentic
attr_accessible :email, :password, :password_confirmation
end
Next, we’re going to modify our database seed file and create a test user that we’ll use to authenticate. In your text editor, modify the seed file to match the example below.
# db/seeds.rb
User.create(email: 'josh@example.com', password: 'passw0rd', password_confirmation: 'passw0rd')
Lastly, we’re going to migrate our changes to the database and then seed it with our test user. In your terminal, run the commands below.
rake db:migrate
rake db:seed
Let’s test our changes. In your terminal run the rails console
commands to load our application. Then, enter the following statement: User.first
. This will query the database and return the first user found. If the application is working properly, the user found should be the user that you used to seed the database.
With the models finished, we can now setup the controller. In this step, we’re going to create a UsersSessionsController
that will be used to allow users to sign in and out of the application.
To generate the UserSessionsController
, open your terminal and run the command below.
rails generate controller UserSessions
Our controller will have four actions. Two will allow users to sign in, one will allow users to sign out, and one will show information about the user that’s currently signed in.
In your text editor, modify the UserSessionsController
to match the example below.
# app/controllers/user_sessions_controller.rb
class UserSessionsController < ApplicationController
def new
@user_session = UserSession.new
end
def create
@user_session = UserSession.new(params[:user_session])
if @user_session.save
flash[:notice] = "Sign in successful!"
redirect_to user_session_url
else
render 'new'
end
end
def show
user_session = UserSession.find
@current_user = user_session.user
end
def destroy
user_session = UserSession.find
user_session.destroy
redirect_to root_url
end
end
Next, we’re going to create two views. The new view will display our sign in form and the show view will be what the user sees when they sign in.
In your text editor, create the new and show views as shown below.
<!-- app/views/user_sessions/new.html.erb -->
<h2>Sign In</h2>
<% if @user_session.errors.any? %>
<div id="error-explanation">
<h3>The following errors occurred:</h3>
<ul>
<% @user_session.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= form_for @user_session, url: user_session_path do |f| %>
<p>
<%= f.label :email %><br/>
<%= f.text_field :email %>
</p>
<p>
<%= f.label :password %><br/>
<%= f.password_field :password %>
</p>
<%= f.submit 'Sign In' %>
<% end %>
<!-- app/views/user_sessions/show.html.erb -->
<h2>Your Session</h2>
<p>
<%= flash[:notice] %>
</p>
<p>
You're signed in as: <b><%= @current_user.email %></b><br/>
<%= link_to 'Sign Out', user_session_path, method: 'delete' %>
</p>
Finally, we need to add the controller as a resource in our routes file. In your text editor, modify the routes files to match the example below.
# config/routes.rb
resource :user_session
root to: 'user_session#new'
Let’s test our changes. In your terminal, run the rails server
command. Then, open your browser and navigate to http://localhost:3000
. You should see a login form. If the application is working properly you should be able to sign in with the test user that you created in the previous step.
This final step will demonstrate how to test with Authlogic. We’re going to create a user to test with and a functional test that will verify that users can sign in and out of the application.
First, let’s create the test user. In your text editor, modify the users fixture to match the example below.
# test/fixtures/users.yml
josh:
email: josh@example.com
password_salt: <%= salt = Authlogic::Random.hex_token %>
crypted_password: <%= Authlogic::CryptoProviders::Sha512.encrypt('passw0rd' + salt) %>
persistence_token: <%= Authlogic::Random.hex_token %>
Now, let’s write the tests. In your text editor, modify the UserSessionsControllerTest
to match the example below.
# test/functional/user_sessions_controller_test.rb
require 'test_helper'
require 'authlogic/test_case'
class UserSessionsControllerTest < ActionController::TestCase
setup :activate_authlogic
test 'it should sign a user in on create' do
post :create, user_session: {
email: 'josh@example.com',
password: 'passw0rd',
password_confirmation: 'passw0rd'
}
assert_equal 'Sign in successful!', flash[:notice]
assert_redirected_to home_url
end
test 'it should sign a user out on destroy' do
UserSession.create(users(:josh))
delete :destroy
assert_nil UserSession.find
assert_redirected_to root_url
end
end
Let’s test our changes. In your terminal, run the rake test
command. If the tests are setup properly, both should pass.
Congratulations! You should be up and running with Authlogic. For more information about Authlogic, check out the project on GitHub. For a more in-depth example, check out the example application.
]]>In this post, I’m going to explain how to configure Vim to display whitespace characters. I’ll also touch on problems you may run into and how to avoid them.
Vim refers to the mode that is used to display whitespace characters as list mode. By default, it’s turned off. To turn it on you can enter set list on the Vim command line or add it to your vimrc file. To turn it off again, you can use the set nolist
command.
List mode is configured to only show the end-of-line characters ($) by default. If you want to show more characters or configure how the characters are displayed you can set the listchars
variable.
listchars
is a global variable whose value can be set to a comma-separated list of key/value pairs. The key represents the whitespace character and the value represents how it will be displayed. For example, the default value for listchars
is eol:$
. This means that when list mode is on end-of-line characters will show up as $.
Options that you can use with listchars
are below. They were taken from the Vim help documentation.
eol - Character to show at the end of each line.
tab - Two characters to be used to show a tab.
trail - Character to show for trailing spaces.
extends - Character to show in the last column when the line continues beyond the right of the screen.
precedes - Character to show in the first column when the line continues beyond the left of the screen.
conceal - Character to show in place of concealed text, when conceallevel is set to 1.
nbsp - Character to show for a space.
Here is how I’ve set listchars
in my configuration:
set listchars=eol:$,nbsp:_,tab:>-,trail:~,extends:>,precedes:<
If you’ve turned on list mode and can’t see whitespace characters, the issue may be with your colorscheme. List mode uses the NonText
and SpecialKey
highlighting groups to determine what color the whitespace characters will be when displayed. In some cases, these highlighting groups may be set to the same color as your background. In short, if the background is black and whitespace characters are black, you won’t see them! Check your colorscheme and make sure these groups are set to a distinct color.
The Vim help documentation is an excellent resource if you know how to find what you’re looking for. You can find more information about list
and a listchars
by entering help list
or help listchars
on the Vim command line.
While considering how I would implement the feature, I spent a few minutes searching for an existing Ruby gem that already provided the functionality I needed. But, I came up empty-handed. Knowing that Nokogiri was a popular choice among Rubyists for parsing HTML files, I decided to try to implement the feature with it instead.
Nokogiri, for those of you who may be new to it, is “an HTML, XML, and SAX parser with the ability to search documents via XPath and CSS selectors” 1. It’s very fast and very powerful. The poject’s site has a few examples of how it can be used to parse, search, and modify HTML and XML documents.
If all you’re interested in is the URLs then parsing a Netscape Bookmark File is trivial. This can easily be done with Nokogiri in a few lines of code. Here’s an example:
require 'nokogiri'
document = Nokogiri::HTML(File.open('bookmarks.html'))
document.css('dt > a').each { |a| puts a['href'] }
This example uses CSS selectors to find all of the anchor tags (or bookmarks) in the document and retuns the text value of each one.
However, in addition to the bookmarks, I was interested in the folders as well. The reason being that I wanted the ability to use the folder names to categorize the bookmarks. This complicated things a bit. Because the bookmarks may be deeply nested within several levels of folders, I would have to traverse the document recursively much like you would if you were traversing a file system.
My first attempt at this was to use Nokogiri’s traverse feature to recursively walk through all of the nodes in the document. The problem with this approach was that traverse descends in to each node of the document as it’s encountered. Since HTML elements containing folder name and folder items were “siblings”, it was very difficult to determine what folder each bookmark belonged to.
After some trial and error, I ended up using a combination of recursion and XPath selectors. This approach allowed me to identify all the bookmarks in the current level of nesting, process them, and then descend to the next level. It works great and I’m pleased with the results. Here’s what I ended up with:
# bookmark_reader.rb
require 'nokogiri'
class Bookmark
attr_accessor :title, :url, :path
def initialize(path, title, url)
@path = path
@title = title
@url = url
end
end
class BookmarkReader
include Enumerable
def initialize(path)
@path = path
end
def each
doc = Nokogiri::HTML(File.open(@path))
node = doc.at_xpath('//html/body')
traverse(node, '/') { |b| yield b }
end
private
def traverse(node, path, &block)
anchors = node.search('./dt//a')
folder_names = node.search('./dt/h3')
folder_items = node.search('./dl')
anchors.each do |anchor|
yield Bookmark.new(path, anchor.text, anchor['href'])
end
folder_items.size.times do |i|
folder_name = folder_names[i]
folder_item = folder_items[i]
next_path = folder_name.nil? ? path : [path, folder_name].join('/')
traverse(folder_item, next_path, &block)
end
end
end
# USAGE
reader = BookmarkReader.new('bookmarks.html')
reader.each { |b| puts b.title }
Parsing the Netscape Bookmark File with Nokogiri ended up being a fun exercise and more of a challenge than I expected. If you have a better solution, I would love to hear from you.
]]>In Vim, this feature is called colorcolumn
. When set, colorcolumn
will change the color of one or more columns in the current window. Using this feature is easy. Simply set the colorcolumn
variable to the value of the column you want to highlight in the vim command line. Below is an example of setting the colorcolumn
to 80.
:set colorcolumn=80
If you want to highlight multiple columns, you can give colorcolumn
a comma-seperated list of values.
:set colorcolumn=80,100
To turn colorcolumn
off, you can simply set the value back to zero.
:set colorcolumn=0
Finally, if you want to change the color, you can use the highlight
command.
:highlight ColorColumn guibg=red
The Vim help documentation is an excellent resource if you know how to find what you’re looking for. You can find more information about colorcolumn
by entering :help colorcolumn
on the Vim command line.
I decided to start by writing a Ruby script that would parse and manipulate only a subset of the data. I used Benchmark to figure out how long it would take the program to run. I then did some quick calculations and the result was that it would take roughly 25 minutes to process the entire data set.
My first attempt looked like this:
require 'benchmark'
require 'csv'
# Read each record in sample.csv, manipulate it,
# and write it to sample.out.csv
bm = Benchmark.realtime do
File.open('sample.out.csv', 'w+') do |output|
CSV.foreach('sample.csv') do |input|
# Do some manipulations...
output.write(input.to_csv)
end
end
end
puts bm
Coincidentally, I had been reading about working with threads and processes in Ruby in the evenings. I thought that this would be a great opportunity to use some of my new knowledge.
According to Ruby’s documentation, Kernel.fork
“creates a subprocess. If a block is specified, the block is run in the subprocess…” The documentation also points out that it should be used with Process.wait
or Process.detach
to avoid accumulating zombie processes.
Here is an example:
fork do
# Do stuff in a subprocess
end
# Wait for the subprocess(es) to finish
Process.wait
Integrating Kernel.fork
into my existing solution was very simple. All I had to do was insert a strategically placed fork
block into my code. The result being that I saved myself and my coworker several extra minutes of waiting.
Here’s what I ended up with:
require 'benchmark'
require 'csv'
bm = Benchmark.realtime do
['file1.csv', 'file2.csv', 'file3.csv'].each do |input_file|
fork do
output_file = input_file + '.out'
File.open(output_file, 'w+') do |output|
CSV.foreach(input_file) do |input|
# Do some manipulations...
output.write(input.to_csv)
end
end
end
end
end
puts bm
You can achieve the same result in Bash using ampersands (&). In Bash, the ampersand is a control operator used to fork processes. This means that if I were to modify the previous example to accept an input file and output file as arguments, I could then run the following command in Bash and achieve similar results:
ruby parse.rb in1.csv out1.csv & \
ruby parse.rb in2.csv out2.csv & \
ruby parse.rb in3.csv out3.csv &
]]>
For example, when working on a small Ruby script, I may want to run it a few times to check the output. In Vim, I can temporarily map <Leader>r
to run the script.
:map ,r :!ruby myscript.rb<cr>
Here's another example. When working with Rails, I may only want to run unit tests on a specific model. In Vim, I can temporarily map <Leader>t
to run only the tests I need.
:map ,t :!rake test TEST=test/unit/product_test<cr>
Using temporary key mappings has saved me many keystrokes. To find out more about this trick (and a lot of other helpful Vim-fu), I highly recommend watching Peepcode's Play By Play with Gary Berhardt. You can also refer to Vim’s documentation on the map command by entering :help map
in Vim’s command line.
One technique that I’ve always liked, but never took time to learn, was displaying a dynamic progress indicator. Chances are you’re seen this yourself. It’s used in popular applications such as Git and Homebrew. The indicators come in various shapes and sizes. I’ve seen progress bars, percentages, spinners, and others.
I’ve created a simple example below so that you can see this technique in action. When you run it, you will see a percentage that dynamically updates in-place as it gradually increases from 0 to 100 over a period of 10 seconds. To try it, open your terminal, start a new irb session, and enter the code below.
# Print 1 to 100 percent in place in the console using "dynamic output"
# technique
1.upto(100) do |i|
printf("\rPercentage: %d%", i)
sleep(0.1)
end
puts
The above example probably looks very similar to code you’ve written in the past. What’s the secret? The key is the \r
character in the first argument of the printf command. This character is known as a carriage return. According to Wikipedia, a carriage return “moves the position of the cursor to the first position on the same line.” This means that each time printf is called inside the loop, the previous line is overwritten - in-place - by a new line. If the carriage return were not included, the new output would be continuously appended to the previous output and the result would look like this: Percentage: 0%Percentage 1%...
Below, I’ve included some additional examples that I’ve seen before in other applications. I’ve also combined them into a gist on GitHub. Feel free to use them or extend them as you see fit.
# Prints a text-based progress bar representing 0 to 100 percent. Each "="
# sign represents 5 percent.
0.step(100, 5) do |i|
printf("\rProgress: [%-20s]", "=" * (i/5))
sleep(0.5)
end
puts
# Prints a text-based "spinner" element while work occurs.
spinner = Enumerator.new do |e|
loop do
e.yield '|'
e.yield '/'
e.yield '-'
e.yield '\\'
end
end
1.upto(100) do |i|
printf("\rSpinner: %s", spinner.next)
sleep(0.1)
end
# Prints a combination of the progress bar, spinner, and percentage examples.
spinner = Enumerator.new do |e|
loop do
e.yield '|'
e.yield '/'
e.yield '-'
e.yield '\\'
end
end
1.upto(100) do |i|
progress = "=" * (i/5) unless i < 5
printf("\rCombined: [%-20s] %d%% %s", progress, i, spinner.next)
sleep(0.1)
end
]]>
If you are concerned with the way long lines are displayed in Vim, then the wrap
setting is for you. It’s turned on by default. When a long line of text reaches the edge of the window, Vim will continue displaying the text on the next line in the same way that Microsoft Word or any other rich text editor would. I find this setting useful when reading log files. Below is an example of how to change it.
" Default. Turn word-wrapping on.
set wrap
" Turn word-wrapping off.
set nowrap
If you are concerned with the way long lines are formatted in the buffer, you can use the textwidth
setting. It’s set to 0 by default. When set to a specific character limit, such as 80, Vim will force any text exceeding that limit onto a new line in the buffer. I find this setting useful when writing a long article, such as a blog post. Below is an example of how to change it.
" Start a new line at 80 characters.
set textwidth=80
" Do not use textwidth
set textwidth=0
What if you’re working with a file that has a lot of long lines and you’d like to reformat them all to a specific number of characters? This simplest way to do this is with the gq
command. When used in conjunction with the textwidth
setting, gq
will reformat the selected lines to the desired length. Below is an example of how you can reformat all of the lines in a file.
" Set the textwidth
set textwidth=80
" Move the cursor to the top of the file
gg
" Select all text in the file
VG
" Reformat all of the lines to the length specified by textwidth
gq
Vim provides many other settings that can be used in conjunction with wrap
and textwidth
. To find out more, you can reference Vim’s help documentation by entering :help wrap
or :help textwidth
on Vim’s command line.