Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Specs for baked out functionality (redux) #51

Merged
merged 20 commits into from Dec 27, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 5 additions & 2 deletions CHANGES.md
Expand Up @@ -5,5 +5,8 @@
* Basic usage information. * Basic usage information.
* Added guard-livereload to Guardfile. * Added guard-livereload to Guardfile.
* Gemfile, rvmrc, rbenv files configured with the ruby version used to generate the app. * Gemfile, rvmrc, rbenv files configured with the ruby version used to generate the app.
* Better specs for auth flows (register, password reset, sign in). * Better specs for auth flows (register, password reset, sign in) (~98% coverage).
* Hardcode 1.9.3-p327 so that app_prototype is executable without futzing. * Use the new rspec expect(...).to syntax ([more info](http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax)).
* Hardcode 1.9.3-p327 so that app_prototype is executable without futzing.
* Consistent hostnames across environments.
* Use mailcatcher when it's running locally ([more info](http://www.mikeperham.com/2012/12/09/12-gems-of-christmas-4-mailcatcher-and-mail_view/)).
3 changes: 3 additions & 0 deletions app_prototype/Gemfile
Expand Up @@ -26,6 +26,7 @@ end
group :test, :development do group :test, :development do
gem 'rspec-rails', '~> 2.12.0' gem 'rspec-rails', '~> 2.12.0'
gem 'capybara', github: 'jnicklas/capybara' # Switch from github once issue #882 is resolved. gem 'capybara', github: 'jnicklas/capybara' # Switch from github once issue #882 is resolved.
gem 'capybara-email'
gem 'factory_girl_rails' gem 'factory_girl_rails'
gem 'jasminerice' gem 'jasminerice'
gem 'timecop' gem 'timecop'
Expand All @@ -34,6 +35,8 @@ end


group :development do group :development do
gem 'foreman' gem 'foreman'
gem 'launchy'
gem 'mailcatcher'
gem 'guard' gem 'guard'
gem 'guard-rspec' gem 'guard-rspec'
gem 'guard-jasmine' gem 'guard-jasmine'
Expand Down
14 changes: 6 additions & 8 deletions app_prototype/app/controllers/password_resets_controller.rb
@@ -1,32 +1,30 @@
class PasswordResetsController < ApplicationController class PasswordResetsController < ApplicationController


skip_before_filter :require_login skip_before_filter :require_login
skip_authorization_check


def create def create
@user = User.find_by_email(params[:email]) @user = User.find_by_email(params[:email])

# Send an email to the user with instructions on how to reset their password. # Send an email to the user with instructions on how to reset their password.
@user.deliver_reset_password_instructions! if @user @user.deliver_reset_password_instructions! if @user

# Tell the user instructions have been sent whether or not email was found. # Tell the user instructions have been sent whether or not email was found.
# This is to not leak information to attackers about which emails exist in the system. # This is to not leak information to attackers about which emails exist in the system.
redirect_to sign_in_path, notice: "Password reset instructions have been sent to your email." redirect_to sign_in_path, notice: "Password reset instructions have been sent to your email."
end end


def edit def edit
@user = User.load_from_reset_password_token(params[:id]) @token = params[:token]
@token = params[:id] @user = User.load_from_reset_password_token(@token)
not_authenticated if !@user not_authenticated if !@user
end end

def update def update
@token = params[:token] # needed to render the form again in case of error @token = params[:token] # needed to render the form again in case of error
@user = User.load_from_reset_password_token(@token) @user = User.load_from_reset_password_token(@token)
not_authenticated if !@user not_authenticated if !@user


# Makes the password confirmation validation work.
@user.password_confirmation = params[:user][:password_confirmation]

# Clear the temporary token and update the password. # Clear the temporary token and update the password.
if @user.change_password!(params[:user][:password]) if @user.change_password!(params[:user][:password])
redirect_to sign_in_path, notice: "Password was successfully updated." redirect_to sign_in_path, notice: "Password was successfully updated."
Expand Down
2 changes: 1 addition & 1 deletion app_prototype/app/controllers/registrations_controller.rb
Expand Up @@ -7,7 +7,7 @@ def new
end end


def create def create
@user = User.new(params[:user]) @user = User.new(params[:user]) # TODO Safe attributes


if @user.save if @user.save
redirect_to sign_in_path, notice: "Thanks for signing up. Please check your email for activation instructions." redirect_to sign_in_path, notice: "Thanks for signing up. Please check your email for activation instructions."
Expand Down
7 changes: 5 additions & 2 deletions app_prototype/app/models/user.rb
Expand Up @@ -4,14 +4,17 @@ class User < ActiveRecord::Base


authenticates_with_sorcery! authenticates_with_sorcery!


validates :name,
length: { maximum: 30 }

validates :email, validates :email,
presence: true, presence: true,
email: true email: true,
uniqueness: true


validates :password, validates :password,
presence: true, presence: true,
length: { minimum: 6 }, length: { minimum: 6 },
confirmation: true,
if: :password if: :password


end end
2 changes: 1 addition & 1 deletion app_prototype/app/views/layouts/application.html.slim
Expand Up @@ -22,7 +22,7 @@ html
ul.dropdown-menu ul.dropdown-menu
li= link_to 'Sign Out', sign_out_path li= link_to 'Sign Out', sign_out_path
- else - else
li= link_to 'Sign in', sign_in_path li= link_to 'Sign In', sign_in_path


- flash.each do |name, msg| - flash.each do |name, msg|
= content_tag :div, raw(msg), class: "alert #{alert_class(name)}" = content_tag :div, raw(msg), class: "alert #{alert_class(name)}"
Expand Down
5 changes: 2 additions & 3 deletions app_prototype/app/views/password_resets/edit.html.slim
@@ -1,13 +1,12 @@
.page-header .page-header
h1 Reset Your Password h1 Reset Your Password


= simple_form_for(@user, url: password_reset_path(@user)) do |f| = simple_form_for(@user, url: reset_password_path(@user)) do |f|
= f.error_notification = f.error_notification


.form-inputs .form-inputs
= f.input :email, disabled: true = f.input :email, disabled: true
= f.input :password, required: true, autofocus: true = f.input :password, label: 'New Password', required: true, autofocus: true
= f.input :password_confirmation, required: true
= hidden_field_tag :token, @token = hidden_field_tag :token, @token


.form-actions .form-actions
Expand Down
4 changes: 2 additions & 2 deletions app_prototype/app/views/password_resets/new.html.slim
@@ -1,11 +1,11 @@
.page-header .page-header
h1 Password Reset h1 Password Reset


= form_tag(password_resets_path, method: :post) do = form_tag(forgotten_password_path, method: :post) do
.control-group .control-group
= label_tag :email, nil, class: 'control-label' = label_tag :email, nil, class: 'control-label'
.controls .controls
= text_field_tag :email, nil, placeholder: 'joe@example.com' = text_field_tag :email, nil, placeholder: 'joe@example.com'


.form-actions .form-actions
= submit_tag "Reset my password!", class: 'btn btn-primary' = submit_tag 'Reset My Password', class: 'btn btn-primary'
3 changes: 1 addition & 2 deletions app_prototype/app/views/registrations/new.html.slim
Expand Up @@ -8,7 +8,6 @@
= f.input :name, autofocus: true = f.input :name, autofocus: true
= f.input :email = f.input :email
= f.input :password = f.input :password
= f.input :password_confirmation


.form-actions .form-actions
= f.button :submit, 'Sign up', class: 'btn btn-primary' = f.button :submit, 'Sign Up', class: 'btn btn-primary'
Expand Up @@ -10,7 +10,7 @@
your username is: <%= @user.email %>.<br/> your username is: <%= @user.email %>.<br/>
</p> </p>
<p> <p>
To login to the site, just follow this link: <%= link_to activate_registration_url(@user.activation_token), activate_registration_url(@user.activation_token) %>. To login to the site, just follow this link: <%= link_to activation_url(@user.activation_token), activation_url(@user.activation_token) %>.
</p> </p>
<p>Thanks for joining and have a great day!</p> <p>Thanks for joining and have a great day!</p>
</body> </body>
Expand Down
Expand Up @@ -4,6 +4,6 @@ Welcome to example.com, <%= @user.email %>
You have successfully signed up to example.com, You have successfully signed up to example.com,
your username is: <%= @user.email %>. your username is: <%= @user.email %>.


To login to the site, just follow this link: <%= activate_registration_url(@user.activation_token) %> To login to the site, just follow this link: <%= activation_url(@user.activation_token) %>


Thanks for joining and have a great day! Thanks for joining and have a great day!
Expand Up @@ -9,7 +9,7 @@
You have requested to reset your password. You have requested to reset your password.
</p> </p>
<p> <p>
To choose a new password, just follow this link: <%= link_to edit_password_reset_url(@user.reset_password_token), edit_password_reset_url(@user.reset_password_token) %>. To choose a new password, just follow this link: <%= link_to reset_password_url(@user.reset_password_token), reset_password_url(@user.reset_password_token) %>.
</p> </p>
<p>Have a great day!</p> <p>Have a great day!</p>
</body> </body>
Expand Down
Expand Up @@ -3,6 +3,6 @@ Hello, <%= @user.email %>


You have requested to reset your password. You have requested to reset your password.


To choose a new password, just follow this link: edit_password_reset_url(@user.reset_password_token) To choose a new password, just follow this link: <%= reset_password_url(@user.reset_password_token) %>


Have a great day! Have a great day!
4 changes: 2 additions & 2 deletions app_prototype/app/views/user_sessions/new.html.slim
Expand Up @@ -6,8 +6,8 @@
= f.input :password = f.input :password


ul.unstyled ul.unstyled
li= link_to 'Sign up', sign_up_path li= link_to 'Sign Up', sign_up_path
li= link_to 'Reset forgotten password', new_password_reset_path li= link_to 'Reset Password', forgotten_password_path


.form-actions .form-actions
= f.button :submit, 'Sign In', class: 'btn btn-primary' = f.button :submit, 'Sign In', class: 'btn btn-primary'
2 changes: 1 addition & 1 deletion app_prototype/app/views/users/show.html.slim
Expand Up @@ -14,4 +14,4 @@ dl


- if can?(:destroy, @user) - if can?(:destroy, @user)
' '
= link_to'Destroy', user_path(@user), method: :delete, data: { confirm: "Are you sure?" }, class: 'btn btn-danger' = link_to 'Destroy', user_path(@user), method: :delete, data: { confirm: "Are you sure?" }, class: 'btn btn-danger'
1 change: 1 addition & 0 deletions app_prototype/config/application.rb
Expand Up @@ -22,6 +22,7 @@ class Application < Rails::Application
#generate.helper false #generate.helper false
generate.routing_specs false generate.routing_specs false
#generate.view_specs false #generate.view_specs false
generate.request_specs false
end end


# Settings in config/environments/* take precedence over those specified here. # Settings in config/environments/* take precedence over those specified here.
Expand Down
11 changes: 11 additions & 0 deletions app_prototype/config/initializers/email.rb
@@ -0,0 +1,11 @@
# http://www.mikeperham.com/2012/12/09/12-gems-of-christmas-4-mailcatcher-and-mail_view/

begin
sock = TCPSocket.new('localhost', 1025)
sock.close
catcher = true
rescue
catcher = false
end

ActionMailer::Base.smtp_settings = (Rails.env.development? && catcher) ? { host: 'localhost', port: '1025', } : {}
14 changes: 9 additions & 5 deletions app_prototype/config/routes.rb
Expand Up @@ -5,12 +5,16 @@


resources :user_sessions, only: [:new, :create, :destroy] resources :user_sessions, only: [:new, :create, :destroy]


resources :registrations, only: [:new, :create, :activate] #resources :registrations, only: [:new, :create, :activate]
match 'sign_up' => 'registrations#new', via: :get match 'sign_up' => 'registrations#new', via: :get, as: :sign_up
match 'sign_up' => 'registrations#create', via: :post match 'sign_up' => 'registrations#create', via: :post, as: :sign_up
match 'sign_up/:token/activate' => 'registrations#activate', via: :get, as: :activate_registration match 'activate/:token' => 'registrations#activate', via: :get, as: :activation


resources :password_resets, only: [:new, :create, :edit, :update] #resources :password_resets, only: [:new, :create, :edit, :update]
match 'forgotten_password' => 'password_resets#new', via: :get, as: :forgotten_password
match 'forgotten_password' => 'password_resets#create', via: :post, as: :forgotten_password
match 'reset_password/:token' => 'password_resets#edit', via: :get, as: :reset_password
match 'reset_password/:id' => 'password_resets#update', via: :put


resources :users resources :users


Expand Down
42 changes: 21 additions & 21 deletions app_prototype/lib/templates/rspec/scaffold/controller_spec.rb
Expand Up @@ -22,39 +22,39 @@ def valid_session
end end


<% unless options[:singleton] -%> <% unless options[:singleton] -%>
describe "GET index" do describe "#index" do
it "assigns all <%= table_name.pluralize %> as @<%= table_name.pluralize %>" do it "assigns all <%= table_name.pluralize %> as @<%= table_name.pluralize %>" do
<%= file_name %> = <%= class_name %>.create! valid_attributes <%= file_name %> = <%= class_name %>.create! valid_attributes
get :index, {}, valid_session get :index, {}, valid_session
assigns(:<%= table_name %>).should eq([<%= file_name %>]) expect(assigns(:<%= table_name %>)).to eq([<%= file_name %>])
end end
end end


<% end -%> <% end -%>
describe "GET show" do describe "#show" do
it "assigns the requested <%= ns_file_name %> as @<%= ns_file_name %>" do it "assigns the requested <%= ns_file_name %> as @<%= ns_file_name %>" do
<%= file_name %> = <%= class_name %>.create! valid_attributes <%= file_name %> = <%= class_name %>.create! valid_attributes
get :show, { :id => <%= file_name %>.to_param }, valid_session get :show, { :id => <%= file_name %>.to_param }, valid_session
assigns(:<%= ns_file_name %>).should eq(<%= file_name %>) expect(assigns(:<%= ns_file_name %>)).to eq(<%= file_name %>)
end end
end end


describe "GET new" do describe "#new" do
it "assigns a new <%= ns_file_name %> as @<%= ns_file_name %>" do it "assigns a new <%= ns_file_name %> as @<%= ns_file_name %>" do
get :new, {}, valid_session get :new, {}, valid_session
assigns(:<%= ns_file_name %>).should be_a_new(<%= class_name %>) expect(assigns(:<%= ns_file_name %>)).to be_a_new(<%= class_name %>)
end end
end end


describe "GET edit" do describe "#edit" do
it "assigns the requested <%= ns_file_name %> as @<%= ns_file_name %>" do it "assigns the requested <%= ns_file_name %> as @<%= ns_file_name %>" do
<%= file_name %> = <%= class_name %>.create! valid_attributes <%= file_name %> = <%= class_name %>.create! valid_attributes
get :edit, { :id => <%= file_name %>.to_param }, valid_session get :edit, { :id => <%= file_name %>.to_param }, valid_session
assigns(:<%= ns_file_name %>).should eq(<%= file_name %>) expect(assigns(:<%= ns_file_name %>)).to eq(<%= file_name %>)
end end
end end


describe "POST create" do describe "#create" do
describe "with valid params" do describe "with valid params" do
it "creates a new <%= class_name %>" do it "creates a new <%= class_name %>" do
expect { expect {
Expand All @@ -64,13 +64,13 @@ def valid_session


it "assigns a newly created <%= ns_file_name %> as @<%= ns_file_name %>" do it "assigns a newly created <%= ns_file_name %> as @<%= ns_file_name %>" do
post :create, {:<%= ns_file_name %> => valid_attributes }, valid_session post :create, {:<%= ns_file_name %> => valid_attributes }, valid_session
assigns(:<%= ns_file_name %>).should be_a(<%= class_name %>) expect(assigns(:<%= ns_file_name %>)).to be_a(<%= class_name %>)
assigns(:<%= ns_file_name %>).should be_persisted expect(assigns(:<%= ns_file_name %>)).to be_persisted
end end


it "redirects to the created <%= ns_file_name %>" do it "redirects to the created <%= ns_file_name %>" do
post :create, { :<%= ns_file_name %> => valid_attributes }, valid_session post :create, { :<%= ns_file_name %> => valid_attributes }, valid_session
response.should redirect_to(<%= class_name %>.last) expect(response).to redirect_to(<%= class_name %>.last)
end end
end end


Expand All @@ -79,19 +79,19 @@ def valid_session
# Trigger the behavior that occurs when invalid params are submitted # Trigger the behavior that occurs when invalid params are submitted
<%= class_name %>.any_instance.stub(:save).and_return(false) <%= class_name %>.any_instance.stub(:save).and_return(false)
post :create, { :<%= ns_file_name %> => <%= formatted_hash(example_invalid_attributes) %> }, valid_session post :create, { :<%= ns_file_name %> => <%= formatted_hash(example_invalid_attributes) %> }, valid_session
assigns(:<%= ns_file_name %>).should be_a_new(<%= class_name %>) expect(assigns(:<%= ns_file_name %>)).to be_a_new(<%= class_name %>)
end end


it "re-renders the 'new' template" do it "re-renders the 'new' template" do
# Trigger the behavior that occurs when invalid params are submitted # Trigger the behavior that occurs when invalid params are submitted
<%= class_name %>.any_instance.stub(:save).and_return(false) <%= class_name %>.any_instance.stub(:save).and_return(false)
post :create, { :<%= ns_file_name %> => <%= formatted_hash(example_invalid_attributes) %> }, valid_session post :create, { :<%= ns_file_name %> => <%= formatted_hash(example_invalid_attributes) %> }, valid_session
response.should render_template("new") expect(response).to render_template("new")
end end
end end
end end


describe "PUT update" do describe "#update" do
describe "with valid params" do describe "with valid params" do
it "updates the requested <%= ns_file_name %>" do it "updates the requested <%= ns_file_name %>" do
<%= file_name %> = <%= class_name %>.create! valid_attributes <%= file_name %> = <%= class_name %>.create! valid_attributes
Expand All @@ -106,13 +106,13 @@ def valid_session
it "assigns the requested <%= ns_file_name %> as @<%= ns_file_name %>" do it "assigns the requested <%= ns_file_name %> as @<%= ns_file_name %>" do
<%= file_name %> = <%= class_name %>.create! valid_attributes <%= file_name %> = <%= class_name %>.create! valid_attributes
put :update, { :id => <%= file_name %>.to_param, :<%= ns_file_name %> => valid_attributes }, valid_session put :update, { :id => <%= file_name %>.to_param, :<%= ns_file_name %> => valid_attributes }, valid_session
assigns(:<%= ns_file_name %>).should eq(<%= file_name %>) expect(assigns(:<%= ns_file_name %>)).to eq(<%= file_name %>)
end end


it "redirects to the <%= ns_file_name %>" do it "redirects to the <%= ns_file_name %>" do
<%= file_name %> = <%= class_name %>.create! valid_attributes <%= file_name %> = <%= class_name %>.create! valid_attributes
put :update, { :id => <%= file_name %>.to_param, :<%= ns_file_name %> => valid_attributes }, valid_session put :update, { :id => <%= file_name %>.to_param, :<%= ns_file_name %> => valid_attributes }, valid_session
response.should redirect_to(<%= file_name %>) expect(response).to redirect_to(<%= file_name %>)
end end
end end


Expand All @@ -122,20 +122,20 @@ def valid_session
# Trigger the behavior that occurs when invalid params are submitted # Trigger the behavior that occurs when invalid params are submitted
<%= class_name %>.any_instance.stub(:save).and_return(false) <%= class_name %>.any_instance.stub(:save).and_return(false)
put :update, { :id => <%= file_name %>.to_param, :<%= ns_file_name %> => <%= formatted_hash(example_invalid_attributes) %> }, valid_session put :update, { :id => <%= file_name %>.to_param, :<%= ns_file_name %> => <%= formatted_hash(example_invalid_attributes) %> }, valid_session
assigns(:<%= ns_file_name %>).should eq(<%= file_name %>) expect(assigns(:<%= ns_file_name %>)).to eq(<%= file_name %>)
end end


it "re-renders the 'edit' template" do it "re-renders the 'edit' template" do
<%= file_name %> = <%= class_name %>.create! valid_attributes <%= file_name %> = <%= class_name %>.create! valid_attributes
# Trigger the behavior that occurs when invalid params are submitted # Trigger the behavior that occurs when invalid params are submitted
<%= class_name %>.any_instance.stub(:save).and_return(false) <%= class_name %>.any_instance.stub(:save).and_return(false)
put :update, { :id => <%= file_name %>.to_param, :<%= ns_file_name %> => <%= formatted_hash(example_invalid_attributes) %> }, valid_session put :update, { :id => <%= file_name %>.to_param, :<%= ns_file_name %> => <%= formatted_hash(example_invalid_attributes) %> }, valid_session
response.should render_template("edit") expect(response).to render_template("edit")
end end
end end
end end


describe "DELETE destroy" do describe "#destroy" do
it "destroys the requested <%= ns_file_name %>" do it "destroys the requested <%= ns_file_name %>" do
<%= file_name %> = <%= class_name %>.create! valid_attributes <%= file_name %> = <%= class_name %>.create! valid_attributes
expect { expect {
Expand All @@ -146,7 +146,7 @@ def valid_session
it "redirects to the <%= table_name %> list" do it "redirects to the <%= table_name %> list" do
<%= file_name %> = <%= class_name %>.create! valid_attributes <%= file_name %> = <%= class_name %>.create! valid_attributes
delete :destroy, { :id => <%= file_name %>.to_param }, valid_session delete :destroy, { :id => <%= file_name %>.to_param }, valid_session
response.should redirect_to(<%= index_helper %>_url) expect(response).to redirect_to(<%= index_helper %>_url)
end end
end end


Expand Down
4 changes: 2 additions & 2 deletions app_prototype/public/index.html
Expand Up @@ -15,7 +15,7 @@
<div class="container"> <div class="container">
<div class="brand">Project_prototype</div> <div class="brand">Project_prototype</div>
<ul class="nav pull-right"> <ul class="nav pull-right">
<li><a href="/sign_in">Sign in</a></li> <li><a href="/sign_in">Sign In</a></li>
</ul> </ul>
</div> </div>
</nav> </nav>
Expand All @@ -29,7 +29,7 @@ <h1>Hello, world!</h1>
<p>Custom generator templates create views that are bootstrap compatible and specs that are factory-aware and follow best practices.</p> <p>Custom generator templates create views that are bootstrap compatible and specs that are factory-aware and follow best practices.</p>
<p>This application also includes authentication and an example of authorization (sign in as user@example.com / password).</p> <p>This application also includes authentication and an example of authorization (sign in as user@example.com / password).</p>


<p><a class="btn btn-primary btn-large" href="sign_in">Sign in</a></p> <p><a class="btn btn-primary btn-large" href="sign_in">Sign In</a></p>
</div> </div>
</div> </div>
<div class="push"></div> <div class="push"></div>
Expand Down