Permalink
Browse files

adding episode 124

  • Loading branch information...
1 parent 1a1e33e commit 42ef78b6afd011d7b45f6ff482f49b7d8f1184e6 @ryanb committed Aug 25, 2008
Showing with 14,414 additions and 270 deletions.
  1. +10 −0 episode-124/README
  2. +3 −0 episode-124/todo/.gitignore
  3. +4 −0 episode-124/todo/README
  4. +10 −0 episode-124/todo/Rakefile
  5. +18 −0 episode-124/todo/app/controllers/application.rb
  6. +4 −0 episode-124/todo/app/controllers/home_controller.rb
  7. +22 −0 episode-124/todo/app/controllers/invitations_controller.rb
  8. +46 −0 episode-124/todo/app/controllers/projects_controller.rb
  9. +40 −0 episode-124/todo/app/controllers/sessions_controller.rb
  10. +38 −0 episode-124/todo/app/controllers/tasks_controller.rb
  11. +24 −0 episode-124/todo/app/controllers/users_controller.rb
  12. +3 −0 episode-124/todo/app/helpers/application_helper.rb
  13. +2 −0 episode-124/todo/app/helpers/home_helper.rb
  14. +2 −0 episode-124/todo/app/helpers/invitations_helper.rb
  15. +23 −0 episode-124/todo/app/helpers/layout_helper.rb
  16. +2 −0 episode-124/todo/app/helpers/projects_helper.rb
  17. +2 −0 episode-124/todo/app/helpers/sessions_helper.rb
  18. +2 −0 episode-124/todo/app/helpers/tasks_helper.rb
  19. +93 −0 episode-124/todo/app/helpers/users_helper.rb
  20. +31 −0 episode-124/todo/app/models/invitation.rb
  21. +9 −0 episode-124/todo/app/models/mailer.rb
  22. +4 −0 episode-124/todo/app/models/project.rb
  23. +3 −0 episode-124/todo/app/models/task.rb
  24. +51 −0 episode-124/todo/app/models/user.rb
  25. +11 −0 episode-124/todo/app/views/home/index.html.erb
  26. +10 −0 episode-124/todo/app/views/invitations/new.html.erb
  27. +24 −0 episode-124/todo/app/views/layouts/application.html.erb
  28. +3 −0 episode-124/todo/app/views/mailer/invitation.erb
  29. +8 −0 episode-124/todo/app/views/projects/_form.html.erb
  30. +8 −0 episode-124/todo/app/views/projects/edit.html.erb
  31. +13 −0 episode-124/todo/app/views/projects/index.html.erb
  32. +5 −0 episode-124/todo/app/views/projects/new.html.erb
  33. +17 −0 episode-124/todo/app/views/projects/show.html.erb
  34. +13 −0 episode-124/todo/app/views/sessions/new.html.erb
  35. +13 −0 episode-124/todo/app/views/tasks/_form.html.erb
  36. +4 −0 episode-124/todo/app/views/tasks/edit.html.erb
  37. +4 −0 episode-124/todo/app/views/tasks/new.html.erb
  38. +13 −0 episode-124/todo/app/views/users/_user_bar.html.erb
  39. +23 −0 episode-124/todo/app/views/users/new.html.erb
  40. +109 −0 episode-124/todo/config/boot.rb
  41. +19 −0 episode-124/todo/config/database.yml
  42. +67 −0 episode-124/todo/config/environment.rb
  43. +17 −0 episode-124/todo/config/environments/development.rb
  44. +22 −0 episode-124/todo/config/environments/production.rb
  45. +22 −0 episode-124/todo/config/environments/test.rb
  46. +10 −0 episode-124/todo/config/initializers/inflections.rb
  47. +5 −0 episode-124/todo/config/initializers/mime_types.rb
  48. +15 −0 episode-124/todo/config/initializers/new_rails_defaults.rb
  49. +38 −0 episode-124/todo/config/initializers/site_keys.rb
  50. +13 −0 episode-124/todo/config/routes.rb
  51. +12 −0 episode-124/todo/db/migrate/20080823221824_create_projects.rb
  52. +14 −0 episode-124/todo/db/migrate/20080823223136_create_tasks.rb
  53. +22 −0 episode-124/todo/db/migrate/20080823232741_create_users.rb
  54. +9 −0 episode-124/todo/db/migrate/20080823233755_add_user_id_to_projects.rb
  55. +15 −0 episode-124/todo/db/migrate/20080825002531_create_invitations.rb
  56. +11 −0 episode-124/todo/db/migrate/20080825002746_add_invitation_to_users.rb
  57. +54 −0 episode-124/todo/db/schema.rb
  58. +2 −0 episode-124/todo/doc/README_FOR_APP
  59. +187 −0 episode-124/todo/lib/authenticated_system.rb
  60. +11 −0 episode-124/todo/lib/authenticated_test_helper.rb
  61. +22 −0 episode-124/todo/lib/tasks/application.rake
  62. +30 −0 episode-124/todo/public/404.html
  63. +30 −0 episode-124/todo/public/422.html
  64. +30 −0 episode-124/todo/public/500.html
  65. +10 −0 episode-124/todo/public/dispatch.cgi
  66. +24 −0 episode-124/todo/public/dispatch.fcgi
  67. +10 −0 episode-124/todo/public/dispatch.rb
  68. 0 episode-124/todo/public/favicon.ico
  69. +2 −0 episode-124/todo/public/javascripts/application.js
  70. +963 −0 episode-124/todo/public/javascripts/controls.js
  71. +972 −0 episode-124/todo/public/javascripts/dragdrop.js
  72. +1,120 −0 episode-124/todo/public/javascripts/effects.js
  73. +4,225 −0 episode-124/todo/public/javascripts/prototype.js
  74. +5 −0 episode-124/todo/public/robots.txt
  75. +88 −0 episode-124/todo/public/stylesheets/application.css
  76. +3 −0 episode-124/todo/script/about
  77. +3 −0 episode-124/todo/script/console
  78. +3 −0 episode-124/todo/script/dbconsole
  79. +3 −0 episode-124/todo/script/destroy
  80. +3 −0 episode-124/todo/script/generate
  81. +3 −0 episode-124/todo/script/performance/benchmarker
  82. +3 −0 episode-124/todo/script/performance/profiler
  83. +3 −0 episode-124/todo/script/performance/request
  84. +3 −0 episode-124/todo/script/plugin
  85. +3 −0 episode-124/todo/script/process/inspector
  86. +3 −0 episode-124/todo/script/process/reaper
  87. +3 −0 episode-124/todo/script/process/spawner
  88. +3 −0 episode-124/todo/script/runner
  89. +3 −0 episode-124/todo/script/server
  90. +11 −0 episode-124/todo/test/fixtures/invitations.yml
  91. +3 −0 episode-124/todo/test/fixtures/mailer/invitation
  92. +5 −0 episode-124/todo/test/fixtures/projects.yml
  93. +9 −0 episode-124/todo/test/fixtures/tasks.yml
  94. +31 −0 episode-124/todo/test/fixtures/users.yml
  95. +8 −0 episode-124/todo/test/functional/home_controller_test.rb
  96. +20 −0 episode-124/todo/test/functional/invitations_controller_test.rb
  97. +54 −0 episode-124/todo/test/functional/projects_controller_test.rb
  98. +82 −0 episode-124/todo/test/functional/sessions_controller_test.rb
  99. +44 −0 episode-124/todo/test/functional/tasks_controller_test.rb
  100. +61 −0 episode-124/todo/test/functional/users_controller_test.rb
  101. +38 −0 episode-124/todo/test/test_helper.rb
  102. +7 −0 episode-124/todo/test/unit/invitation_test.rb
  103. +13 −0 episode-124/todo/test/unit/mailer_test.rb
  104. +7 −0 episode-124/todo/test/unit/project_test.rb
  105. +7 −0 episode-124/todo/test/unit/task_test.rb
  106. +103 −0 episode-124/todo/test/unit/user_test.rb
  107. +20 −0 episode-124/todo/vendor/plugins/restful-authentication/.gitignore
  108. +68 −0 episode-124/todo/vendor/plugins/restful-authentication/CHANGELOG
  109. +220 −0 episode-124/todo/vendor/plugins/restful-authentication/README.textile
  110. +22 −0 episode-124/todo/vendor/plugins/restful-authentication/Rakefile
  111. +15 −0 episode-124/todo/vendor/plugins/restful-authentication/TODO
  112. +1 −0 episode-124/todo/vendor/plugins/restful-authentication/generators/authenticated/USAGE
  113. +478 −0 ...24/todo/vendor/plugins/restful-authentication/generators/authenticated/authenticated_generator.rb
  114. +54 −0 episode-124/todo/vendor/plugins/restful-authentication/generators/authenticated/lib/insert_routes.rb
  115. +8 −0 .../vendor/plugins/restful-authentication/generators/authenticated/templates/_model_partial.html.erb
  116. +3 −0 ...-124/todo/vendor/plugins/restful-authentication/generators/authenticated/templates/activation.erb
  117. +187 −0 .../vendor/plugins/restful-authentication/generators/authenticated/templates/authenticated_system.rb
  118. +22 −0 ...or/plugins/restful-authentication/generators/authenticated/templates/authenticated_test_helper.rb
  119. +43 −0 ...e-124/todo/vendor/plugins/restful-authentication/generators/authenticated/templates/controller.rb
  120. +2 −0 episode-124/todo/vendor/plugins/restful-authentication/generators/authenticated/templates/helper.rb
  121. +16 −0 ...-124/todo/vendor/plugins/restful-authentication/generators/authenticated/templates/login.html.erb
  122. +25 −0 episode-124/todo/vendor/plugins/restful-authentication/generators/authenticated/templates/mailer.rb
  123. +26 −0 ...de-124/todo/vendor/plugins/restful-authentication/generators/authenticated/templates/migration.rb
  124. +74 −0 episode-124/todo/vendor/plugins/restful-authentication/generators/authenticated/templates/model.rb
  125. +86 −0 ...todo/vendor/plugins/restful-authentication/generators/authenticated/templates/model_controller.rb
  126. +93 −0 ...124/todo/vendor/plugins/restful-authentication/generators/authenticated/templates/model_helper.rb
  127. +158 −0 ...odo/vendor/plugins/restful-authentication/generators/authenticated/templates/model_helper_spec.rb
  128. +11 −0 ...ode-124/todo/vendor/plugins/restful-authentication/generators/authenticated/templates/observer.rb
  129. +19 −0 ...124/todo/vendor/plugins/restful-authentication/generators/authenticated/templates/signup.html.erb
  130. +8 −0 .../vendor/plugins/restful-authentication/generators/authenticated/templates/signup_notification.erb
  131. +38 −0 ...de-124/todo/vendor/plugins/restful-authentication/generators/authenticated/templates/site_keys.rb
  132. +90 −0 ...restful-authentication/generators/authenticated/templates/spec/controllers/access_control_spec.rb
  133. +101 −0 ...l-authentication/generators/authenticated/templates/spec/controllers/authenticated_system_spec.rb
  134. +139 −0 ...ul-authentication/generators/authenticated/templates/spec/controllers/sessions_controller_spec.rb
  135. +198 −0 ...stful-authentication/generators/authenticated/templates/spec/controllers/users_controller_spec.rb
  136. +60 −0 .../vendor/plugins/restful-authentication/generators/authenticated/templates/spec/fixtures/users.yml
  137. +141 −0 ...ugins/restful-authentication/generators/authenticated/templates/spec/helpers/users_helper_spec.rb
  138. +290 −0 ...vendor/plugins/restful-authentication/generators/authenticated/templates/spec/models/user_spec.rb
  139. +22 −0 ...or/plugins/restful-authentication/generators/authenticated/templates/stories/rest_auth_stories.rb
  140. +81 −0 ...ins/restful-authentication/generators/authenticated/templates/stories/rest_auth_stories_helper.rb
  141. +49 −0 ...ns/restful-authentication/generators/authenticated/templates/stories/steps/ra_navigation_steps.rb
  142. +179 −0 ...gins/restful-authentication/generators/authenticated/templates/stories/steps/ra_resource_steps.rb
  143. +171 −0 ...gins/restful-authentication/generators/authenticated/templates/stories/steps/ra_response_steps.rb
  144. +153 −0 ...dor/plugins/restful-authentication/generators/authenticated/templates/stories/steps/user_steps.rb
  145. +186 −0 ...or/plugins/restful-authentication/generators/authenticated/templates/stories/users/accounts.story
  146. +134 −0 ...or/plugins/restful-authentication/generators/authenticated/templates/stories/users/sessions.story
  147. +82 −0 .../vendor/plugins/restful-authentication/generators/authenticated/templates/test/functional_test.rb
  148. +31 −0 ...todo/vendor/plugins/restful-authentication/generators/authenticated/templates/test/mailer_test.rb
  149. +93 −0 ...r/plugins/restful-authentication/generators/authenticated/templates/test/model_functional_test.rb
  150. +164 −0 ...4/todo/vendor/plugins/restful-authentication/generators/authenticated/templates/test/unit_test.rb
  151. +3 −0 episode-124/todo/vendor/plugins/restful-authentication/init.rb
  152. +1 −0 episode-124/todo/vendor/plugins/restful-authentication/install.rb
  153. +43 −0 episode-124/todo/vendor/plugins/restful-authentication/lib/authentication.rb
  154. +85 −0 episode-124/todo/vendor/plugins/restful-authentication/lib/authentication/by_cookie_token.rb
  155. +65 −0 episode-124/todo/vendor/plugins/restful-authentication/lib/authentication/by_password.rb
  156. +15 −0 episode-124/todo/vendor/plugins/restful-authentication/lib/authorization.rb
  157. +64 −0 episode-124/todo/vendor/plugins/restful-authentication/lib/authorization/aasm_roles.rb
  158. +63 −0 episode-124/todo/vendor/plugins/restful-authentication/lib/authorization/stateful_roles.rb
  159. +15 −0 episode-124/todo/vendor/plugins/restful-authentication/lib/trustification.rb
  160. +20 −0 episode-124/todo/vendor/plugins/restful-authentication/lib/trustification/email_validation.rb
  161. +2 −0 episode-124/todo/vendor/plugins/restful-authentication/notes/AccessControl.txt
  162. +5 −0 episode-124/todo/vendor/plugins/restful-authentication/notes/Authentication.txt
  163. +154 −0 episode-124/todo/vendor/plugins/restful-authentication/notes/Authorization.txt
  164. +78 −0 episode-124/todo/vendor/plugins/restful-authentication/notes/RailsPlugins.txt
  165. BIN episode-124/todo/vendor/plugins/restful-authentication/notes/SecurityFramework.graffle
  166. BIN episode-124/todo/vendor/plugins/restful-authentication/notes/SecurityFramework.png
  167. +163 −0 episode-124/todo/vendor/plugins/restful-authentication/notes/SecurityPatterns.txt
  168. +126 −0 episode-124/todo/vendor/plugins/restful-authentication/notes/Tradeoffs.txt
  169. +49 −0 episode-124/todo/vendor/plugins/restful-authentication/notes/Trustification.txt
  170. +33 −0 episode-124/todo/vendor/plugins/restful-authentication/tasks/auth.rake
  171. +3 −255 templates/todo/README
  172. +1 −15 templates/todo/db/schema.rb
View
@@ -0,0 +1,10 @@
+Railscasts Episode #124: Beta Invitations
+
+http://railscasts.com/episodes/124
+
+Commands
+
+ script/generate nifty_scaffold invitation sender_id:integer recipient_email:string token:string sent_at:datetime new
+ script/generate migration add_invitation_to_users invitation_id:integer invitation_limit:integer
+ script/generate mailer Mailer invitation
+
@@ -0,0 +1,3 @@
+tmp/*
+log/*
+*.sqlite3
View
@@ -0,0 +1,4 @@
+Railscasts Example To Do App
+--
+
+To setup the app, just run `rake setup`.
View
@@ -0,0 +1,10 @@
+# Add your own tasks in files placed in lib/tasks ending in .rake,
+# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
+
+require(File.join(File.dirname(__FILE__), 'config', 'boot'))
+
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+require 'tasks/rails'
@@ -0,0 +1,18 @@
+# Filters added to this controller apply to all controllers in the application.
+# Likewise, all the methods added will be available for all controllers.
+
+class ApplicationController < ActionController::Base
+ helper :all # include all helpers, all the time
+
+ # See ActionController::RequestForgeryProtection for details
+ # Uncomment the :secret if you're not using the cookie session store
+ protect_from_forgery # :secret => '9ae178eac1fbbd4062a93c8c558a12ef'
+
+ # See ActionController::Base for details
+ # Uncomment this to filter the contents of submitted sensitive data parameters
+ # from your application log (in this case, all fields with names like "password").
+ # filter_parameter_logging :password
+
+ # for restful authentication
+ include AuthenticatedSystem
+end
@@ -0,0 +1,4 @@
+class HomeController < ApplicationController
+ def index
+ end
+end
@@ -0,0 +1,22 @@
+class InvitationsController < ApplicationController
+ def new
+ @invitation = Invitation.new
+ end
+
+ def create
+ @invitation = Invitation.new(params[:invitation])
+ @invitation.sender = current_user
+ if @invitation.save
+ if logged_in?
+ Mailer.deliver_invitation(@invitation, signup_url(@invitation.token))
+ flash[:notice] = "Thank you, invitation sent."
+ redirect_to projects_url
+ else
+ flash[:notice] = "Thank you, we will notify when we are ready."
+ redirect_to root_url
+ end
+ else
+ render :action => 'new'
+ end
+ end
+end
@@ -0,0 +1,46 @@
+class ProjectsController < ApplicationController
+ before_filter :login_required
+
+ def index
+ @projects = current_user.projects.find(:all)
+ end
+
+ def show
+ @project = current_user.projects.find(params[:id])
+ end
+
+ def new
+ @project = current_user.projects.build
+ end
+
+ def create
+ @project = current_user.projects.build(params[:project])
+ if @project.save
+ flash[:notice] = "Successfully created project."
+ redirect_to @project
+ else
+ render :action => 'new'
+ end
+ end
+
+ def edit
+ @project = current_user.projects.find(params[:id])
+ end
+
+ def update
+ @project = current_user.projects.find(params[:id])
+ if @project.update_attributes(params[:project])
+ flash[:notice] = "Successfully updated project."
+ redirect_to @project
+ else
+ render :action => 'edit'
+ end
+ end
+
+ def destroy
+ @project = current_user.projects.find(params[:id])
+ @project.destroy
+ flash[:notice] = "Successfully destroyed project."
+ redirect_to projects_url
+ end
+end
@@ -0,0 +1,40 @@
+# This controller handles the login/logout function of the site.
+class SessionsController < ApplicationController
+ # render new.rhtml
+ def new
+ end
+
+ def create
+ logout_keeping_session!
+ user = User.authenticate(params[:login], params[:password])
+ if user
+ # Protects against session fixation attacks, causes request forgery
+ # protection if user resubmits an earlier form using back
+ # button. Uncomment if you understand the tradeoffs.
+ # reset_session
+ self.current_user = user
+ new_cookie_flag = (params[:remember_me] == "1")
+ handle_remember_cookie! new_cookie_flag
+ projects_url
+ flash[:notice] = "Logged in successfully"
+ else
+ note_failed_signin
+ @login = params[:login]
+ @remember_me = params[:remember_me]
+ render :action => 'new'
+ end
+ end
+
+ def destroy
+ logout_killing_session!
+ flash[:notice] = "You have been logged out."
+ redirect_back_or_default('/')
+ end
+
+protected
+ # Track failed login attempts
+ def note_failed_signin
+ flash[:error] = "Couldn't log you in as '#{params[:login]}'"
+ logger.warn "Failed login for '#{params[:login]}' from #{request.remote_ip} at #{Time.now.utc}"
+ end
+end
@@ -0,0 +1,38 @@
+class TasksController < ApplicationController
+ before_filter :login_required
+
+ def new
+ @task = Task.new(:project_id => params[:project_id])
+ end
+
+ def create
+ @task = Task.new(params[:task])
+ if @task.save
+ flash[:notice] = "Successfully created task."
+ redirect_to @task.project
+ else
+ render :action => 'new'
+ end
+ end
+
+ def edit
+ @task = current_user.tasks.find(params[:id])
+ end
+
+ def update
+ @task = current_user.tasks.find(params[:id])
+ if @task.update_attributes(params[:task])
+ flash[:notice] = "Successfully updated task."
+ redirect_to @task.project
+ else
+ render :action => 'edit'
+ end
+ end
+
+ def destroy
+ @task = current_user.tasks.find(params[:id])
+ @task.destroy
+ flash[:notice] = "Successfully destroyed task."
+ redirect_to @task.project
+ end
+end
@@ -0,0 +1,24 @@
+class UsersController < ApplicationController
+ # render new.rhtml
+ def new
+ @user = User.new(:invitation_token => params[:invitation_token])
+ @user.email = @user.invitation.recipient_email if @user.invitation
+ end
+
+ def create
+ logout_keeping_session!
+ @user = User.new(params[:user])
+ success = @user && @user.save
+ if success && @user.errors.empty?
+ # Protects against session fixation attacks, causes request forgery
+ # protection if visitor resubmits an earlier form using back
+ # button. Uncomment if you understand the tradeoffs.
+ # reset session
+ self.current_user = @user # !! now logged in
+ redirect_to projects_url
+ else
+ flash[:error] = "We couldn't set up that account, sorry. Please try again, or contact an admin (link is above)."
+ render :action => 'new'
+ end
+ end
+end
@@ -0,0 +1,3 @@
+# Methods added to this helper will be available to all templates in the application.
+module ApplicationHelper
+end
@@ -0,0 +1,2 @@
+module HomeHelper
+end
@@ -0,0 +1,2 @@
+module InvitationsHelper
+end
@@ -0,0 +1,23 @@
+# These helper methods can be called in your template to set variables to be used in the layout
+# This module should be included in all views globally,
+# to do so you may need to add this line to your ApplicationController
+# helper :layout
+module LayoutHelper
+ def title(page_title, show_title = true)
+ @content_for_title = page_title.to_s
+ @show_title = show_title
+ end
+
+ def show_title?
+ @show_title
+ end
+
+ def stylesheet(*args)
+ content_for(:head) { stylesheet_link_tag(*args.map(&:to_s)) }
+ end
+
+ def javascript(*args)
+ args = args.map { |arg| arg == :defaults ? arg : arg.to_s }
+ content_for(:head) { javascript_include_tag(*args) }
+ end
+end
@@ -0,0 +1,2 @@
+module ProjectsHelper
+end
@@ -0,0 +1,2 @@
+module SessionsHelper
+end
@@ -0,0 +1,2 @@
+module TasksHelper
+end
@@ -0,0 +1,93 @@
+module UsersHelper
+
+ #
+ # Use this to wrap view elements that the user can't access.
+ # !! Note: this is an *interface*, not *security* feature !!
+ # You need to do all access control at the controller level.
+ #
+ # Example:
+ # <%= if_authorized?(:index, User) do link_to('List all users', users_path) end %> |
+ # <%= if_authorized?(:edit, @user) do link_to('Edit this user', edit_user_path) end %> |
+ # <%= if_authorized?(:destroy, @user) do link_to 'Destroy', @user, :confirm => 'Are you sure?', :method => :delete end %>
+ #
+ #
+ def if_authorized?(action, resource, &block)
+ if authorized?(action, resource)
+ yield action, resource
+ end
+ end
+
+ #
+ # Link to user's page ('users/1')
+ #
+ # By default, their login is used as link text and link title (tooltip)
+ #
+ # Takes options
+ # * :content_text => 'Content text in place of user.login', escaped with
+ # the standard h() function.
+ # * :content_method => :user_instance_method_to_call_for_content_text
+ # * :title_method => :user_instance_method_to_call_for_title_attribute
+ # * as well as link_to()'s standard options
+ #
+ # Examples:
+ # link_to_user @user
+ # # => <a href="/users/3" title="barmy">barmy</a>
+ #
+ # # if you've added a .name attribute:
+ # content_tag :span, :class => :vcard do
+ # (link_to_user user, :class => 'fn n', :title_method => :login, :content_method => :name) +
+ # ': ' + (content_tag :span, user.email, :class => 'email')
+ # end
+ # # => <span class="vcard"><a href="/users/3" title="barmy" class="fn n">Cyril Fotheringay-Phipps</a>: <span class="email">barmy@blandings.com</span></span>
+ #
+ # link_to_user @user, :content_text => 'Your user page'
+ # # => <a href="/users/3" title="barmy" class="nickname">Your user page</a>
+ #
+ def link_to_user(user, options={})
+ raise "Invalid user" unless user
+ options.reverse_merge! :content_method => :login, :title_method => :login, :class => :nickname
+ content_text = options.delete(:content_text)
+ content_text ||= user.send(options.delete(:content_method))
+ options[:title] ||= user.send(options.delete(:title_method))
+ link_to h(content_text), user_path(user), options
+ end
+
+ #
+ # Link to login page using remote ip address as link content
+ #
+ # The :title (and thus, tooltip) is set to the IP address
+ #
+ # Examples:
+ # link_to_login_with_IP
+ # # => <a href="/login" title="169.69.69.69">169.69.69.69</a>
+ #
+ # link_to_login_with_IP :content_text => 'not signed in'
+ # # => <a href="/login" title="169.69.69.69">not signed in</a>
+ #
+ def link_to_login_with_IP content_text=nil, options={}
+ ip_addr = request.remote_ip
+ content_text ||= ip_addr
+ options.reverse_merge! :title => ip_addr
+ if tag = options.delete(:tag)
+ content_tag tag, h(content_text), options
+ else
+ link_to h(content_text), login_path, options
+ end
+ end
+
+ #
+ # Link to the current user's page (using link_to_user) or to the login page
+ # (using link_to_login_with_IP).
+ #
+ def link_to_current_user(options={})
+ if current_user
+ link_to_user current_user, options
+ else
+ content_text = options.delete(:content_text) || 'not signed in'
+ # kill ignored options from link_to_user
+ [:content_method, :title_method].each{|opt| options.delete(opt)}
+ link_to_login_with_IP content_text, options
+ end
+ end
+
+end
@@ -0,0 +1,31 @@
+class Invitation < ActiveRecord::Base
+ belongs_to :sender, :class_name => 'User'
+ has_one :recipient, :class_name => 'User'
+
+ validates_presence_of :recipient_email
+ validate :recipient_is_not_registered
+ validate :sender_has_invitations, :if => :sender
+
+ before_create :generate_token
+ before_create :decrement_sender_count, :if => :sender
+
+private
+
+ def recipient_is_not_registered
+ errors.add :recipient_email, 'is already registered' if User.find_by_email(recipient_email)
+ end
+
+ def sender_has_invitations
+ unless sender.invitation_limit > 0
+ errors.add_to_base 'You have reached your limit of invitations to send.'
+ end
+ end
+
+ def generate_token
+ self.token = Digest::SHA1.hexdigest([Time.now, rand].join)
+ end
+
+ def decrement_sender_count
+ sender.decrement! :invitation_limit
+ end
+end
Oops, something went wrong.

0 comments on commit 42ef78b

Please sign in to comment.