Skip to content

Commit

Permalink
rails_apps_composer: prelaunch app
Browse files Browse the repository at this point in the history
  • Loading branch information
Dave Ekhaus committed Apr 20, 2013
1 parent 3c3fcaa commit d6ee754
Show file tree
Hide file tree
Showing 31 changed files with 596 additions and 131 deletions.
53 changes: 53 additions & 0 deletions app/assets/javascripts/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,56 @@
//= require jquery_ujs
//= require bootstrap
//= require_tree .
$('document').ready(function() {

// display validation errors for the "request invitation" form
if ($('.alert-error').length > 0) {
$("#request-invite").modal('toggle');
}

// use AJAX to submit the "request invitation" form
$('#invitation_button').on('click', function() {
var email = $('form #user_email').val();
var dataString = 'user[email]='+ email
$.ajax({
type: "POST",
url: "/users",
data: dataString,
success: function(data) {
$('#request-invite').html(data);
loadSocial();
}
});
return false;
});

})

// load social sharing scripts if the page includes a Twitter "share" button
function loadSocial() {

//Twitter
if (typeof (twttr) != 'undefined') {
twttr.widgets.load();
} else {
$.getScript('http://platform.twitter.com/widgets.js');
}

//Facebook
if (typeof (FB) != 'undefined') {
FB.init({ status: true, cookie: true, xfbml: true });
} else {
$.getScript("http://connect.facebook.net/en_US/all.js#xfbml=1", function () {
FB.init({ status: true, cookie: true, xfbml: true });
});
}

//Google+
if (typeof (gapi) != 'undefined') {
$(".g-plusone").each(function () {
gapi.plusone.render($(this).get(0));
});
} else {
$.getScript('https://apis.google.com/js/plusone.js');
}
}
84 changes: 84 additions & 0 deletions app/controllers/confirmations_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
class ConfirmationsController < Devise::PasswordsController
# Remove the first skip_before_filter (:require_no_authentication) if you
# don't want to enable logged users to access the confirmation page.
skip_before_filter :require_no_authentication
skip_before_filter :authenticate_user!

# POST /resource/confirmation
def create
self.resource = resource_class.send_confirmation_instructions(resource_params)
if successfully_sent?(resource)
respond_with({}, :location => after_resending_confirmation_instructions_path_for(resource_name))
else
respond_with(resource)
end
end

# PUT /resource/confirmation
def update
with_unconfirmed_confirmable do
if @confirmable.has_no_password?
@confirmable.attempt_set_password(params[:user])
if @confirmable.valid?
do_confirm
else
do_show
@confirmable.errors.clear #so that we won't render :new
end
else
self.class.add_error_on(self, :email, :password_allready_set)
end
end

if !@confirmable.errors.empty?
render 'devise/confirmations/new'
end
end

# GET /resource/confirmation?confirmation_token=abcdef
def show
with_unconfirmed_confirmable do
if @confirmable.has_no_password?
do_show
else
do_confirm
end
end
if !@confirmable.errors.empty?
render 'devise/confirmations/new'
end
end

protected

def with_unconfirmed_confirmable
@confirmable = User.find_or_initialize_with_error_by(:confirmation_token, params[:confirmation_token])
self.resource = @confirmable
if !@confirmable.new_record?
@confirmable.only_if_unconfirmed {yield}
end
end

def do_show
@confirmation_token = params[:confirmation_token]
@requires_password = true
render 'devise/confirmations/show'
end

def do_confirm
@confirmable.confirm!
set_flash_message :notice, :confirmed
sign_in_and_redirect(resource_name, @confirmable)
end

# The path used after resending confirmation instructions.
def after_resending_confirmation_instructions_path_for(resource_name)
new_session_path(resource_name)
end

# The path used after confirmation.
def after_confirmation_path_for(resource_name, resource)
after_sign_in_path_for(resource)
end

end
3 changes: 0 additions & 3 deletions app/controllers/home_controller.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
class HomeController < ApplicationController
def index
@users = User.all
end
end
34 changes: 34 additions & 0 deletions app/controllers/registrations_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
class RegistrationsController < Devise::RegistrationsController

# override #create to respond to AJAX with a partial
def create
build_resource

if resource.save
if resource.active_for_authentication?
sign_in(resource_name, resource)
(render(:partial => 'thankyou', :layout => false) && return) if request.xhr?
respond_with resource, :location => after_sign_up_path_for(resource)
else
expire_session_data_after_sign_in!
(render(:partial => 'thankyou', :layout => false) && return) if request.xhr?
respond_with resource, :location => after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
render :action => :new, :layout => !request.xhr?
end
end

protected

def after_inactive_sign_up_path_for(resource)
'/thankyou.html'
end

def after_sign_up_path_for(resource)
# the page new users will see after sign up (after launch, when no invitation is needed)
redirect_to root_path
end

end
33 changes: 15 additions & 18 deletions app/controllers/users_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,22 @@ def index
def show
@user = User.find(params[:id])
end
def update
authorize! :update, @user, :message => 'Not authorized as an administrator.'

def invite
authorize! :invite, @user, :message => 'Not authorized as an administrator.'
@user = User.find(params[:id])
if @user.update_attributes(params[:user], :as => :admin)
redirect_to users_path, :notice => "User updated."
else
redirect_to users_path, :alert => "Unable to update user."
end
@user.send_confirmation_instructions
redirect_to :back, :only_path => true, :notice => "Sent invitation to #{@user.email}."
end

def destroy
authorize! :destroy, @user, :message => 'Not authorized as an administrator.'
user = User.find(params[:id])
unless user == current_user
user.destroy
redirect_to users_path, :notice => "User deleted."
else
redirect_to users_path, :notice => "Can't delete yourself."

def bulk_invite
authorize! :bulk_invite, @user, :message => 'Not authorized as an administrator.'
users = User.where(:confirmation_token => nil).order(:created_at).limit(params[:quantity])
count = users.count
users.each do |user|
user.send_confirmation_instructions
end
redirect_to :back, :only_path => true, :notice => "Sent invitation to #{count} users."
end
end

end
9 changes: 9 additions & 0 deletions app/mailers/user_mailer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class UserMailer < ActionMailer::Base
default :from => ENV["EMAIL_ADDRESS"]

def welcome_email(user)
mail(:to => user.email, :subject => "Invitation Request Received")
headers['X-MC-GoogleAnalytics'] = ENV["DOMAIN"]
headers['X-MC-Tags'] = "welcome"
end
end
87 changes: 83 additions & 4 deletions app/models/user.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,92 @@
class User < ActiveRecord::Base
rolify
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :trackable, :validatable

# Setup accessible (or protected) attributes for your model
attr_accessible :role_ids, :as => :admin
attr_accessible :name, :email, :password, :password_confirmation, :remember_me


after_create :add_user_to_mailchimp
before_destroy :remove_user_from_mailchimp

# override Devise method
# no password is required when the account is created; validate password when the user sets one
validates_confirmation_of :password
def password_required?
if !persisted?
!(password != "")
else
!password.nil? || !password_confirmation.nil?
end
end

# override Devise method
def confirmation_required?
false
end

# override Devise method
def active_for_authentication?
confirmed? || confirmation_period_valid?
end

def send_reset_password_instructions
if self.confirmed?
super
else
errors.add :base, "You must receive an invitation before you set your password."
end
end

# new function to set the password
def attempt_set_password(params)
p = {}
p[:password] = params[:password]
p[:password_confirmation] = params[:password_confirmation]
update_attributes(p)
end

# new function to determine whether a password has been set
def has_no_password?
self.encrypted_password.blank?
end

# new function to provide access to protected method pending_any_confirmation
def only_if_unconfirmed
pending_any_confirmation {yield}
end

private

def add_user_to_mailchimp
return if email.include?(ENV['ADMIN_EMAIL'])
mailchimp = Gibbon.new
result = mailchimp.list_subscribe({
:id => ENV['MAILCHIMP_LIST_ID'],
:email_address => self.email,
:double_optin => false,
:update_existing => true,
:send_welcome => true
})
Rails.logger.info("Subscribed #{self.email} to MailChimp") if result
rescue Gibbon::MailChimpError => e
Rails.logger.info("MailChimp subscribe failed for #{self.email}: " + e.message)
end

def remove_user_from_mailchimp
mailchimp = Gibbon.new
result = mailchimp.list_unsubscribe({
:id => ENV['MAILCHIMP_LIST_ID'],
:email_address => self.email,
:delete_member => true,
:send_goodbye => false,
:send_notify => true
})
Rails.logger.info("Unsubscribed #{self.email} from MailChimp") if result
rescue Gibbon::MailChimpError => e
Rails.logger.info("MailChimp unsubscribe failed for #{self.email}: " + e.message)
end

end
24 changes: 24 additions & 0 deletions app/views/devise/confirmations/show.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<h2>Account Activation</h2>
<%= simple_form_for resource, :as => resource_name, :url => update_user_confirmation_path, :html => {:class => 'form-horizontal', :method => 'put'}, :id => 'activation-form' do |f| %>
<%= devise_error_messages! %>
<fieldset>
<legend>
Account Activation
<% if resource.email %>
for <%= resource.email %>
<% end %>
</legend>
<% if @requires_password %>
<p>
<%= f.label :password,'Choose a Password:' %>
<%= f.password_field :password %>
</p>
<p>
<%= f.label :password_confirmation, 'Password Confirmation:' %>
<%= f.password_field :password_confirmation %>
</p>
<% end %>
<%= hidden_field_tag :confirmation_token, @confirmation_token %>
<p><%= f.submit "Activate" %></p>
</fieldset>
<% end %>
7 changes: 7 additions & 0 deletions app/views/devise/mailer/confirmation_instructions.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<p>Welcome <%= @resource.email %>!</p>

<p>We're pleased to invite you to try <%= link_to ENV["DOMAIN"], root_url %>.</p>

<p>Please click the link below to confirm your email address and set your password:</p>

<p><%= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token) %></p>
21 changes: 21 additions & 0 deletions app/views/devise/registrations/_thankyou.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<h1>Thank you</h1>
<div id="request-invite" class="modal" style="display: 'block';">
<div class="modal-header">
<a class="close" data-dismiss="modal">&#215;</a>
<h3>Thank you!</h3>
</div>
<div class="modal-body" style="margin-bottom: 120px; overflow: visible">
<p>We have received your request for an invitation to example.com.</p>
<p>We'll contact you when we launch.</p>
<p>Share your discovery with your friends!</p>
<div id="tweet" style="display:inline-block;">
<a class="twitter-share-button" data-count="horizontal" data-text="A new site I've discovered" data-url="http://railsapps.github.com/rails-prelaunch-signup/" data-via="rails_apps" data-related="rails_apps" href="https://twitter.com/share"></a>
</div>
<span style="display:inline-block; vertical-align:text-bottom;">
<div class="fb-like" data-href="http://railsapps.github.com/rails-prelaunch-signup/" data-layout="button_count" data-send="false" data-show-faces="false" data-width="90">
</div>
</span>
<div class="g-plusone" data-annotation="inline" data-href="http://railsapps.github.com/rails-prelaunch-signup/" data-size="medium" data-width="120">
</div>
</div>
</div>
Loading

0 comments on commit d6ee754

Please sign in to comment.