sparkly-auth 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +20 -0
- data/README.rdoc +17 -0
- data/Rakefile +50 -0
- data/VERSION +1 -0
- data/app/controllers/sparkly_accounts_controller.rb +59 -0
- data/app/controllers/sparkly_controller.rb +47 -0
- data/app/controllers/sparkly_sessions_controller.rb +52 -0
- data/app/models/password.rb +3 -0
- data/app/models/remembrance_token.rb +50 -0
- data/app/views/sparkly_accounts/edit.html.erb +24 -0
- data/app/views/sparkly_accounts/new.html.erb +24 -0
- data/app/views/sparkly_accounts/show.html.erb +0 -0
- data/app/views/sparkly_sessions/new.html.erb +22 -0
- data/dependencies.rb +1 -0
- data/generators/sparkly/USAGE +27 -0
- data/generators/sparkly/sparkly_generator.rb +76 -0
- data/generators/sparkly/templates/accounts_controller.rb +65 -0
- data/generators/sparkly/templates/accounts_helper.rb +2 -0
- data/generators/sparkly/templates/help_file.txt +56 -0
- data/generators/sparkly/templates/initializer.rb +30 -0
- data/generators/sparkly/templates/migrations/add_confirmed_to_sparkly_passwords.rb +9 -0
- data/generators/sparkly/templates/migrations/create_sparkly_passwords.rb +19 -0
- data/generators/sparkly/templates/migrations/create_sparkly_remembered_tokens.rb +15 -0
- data/generators/sparkly/templates/sessions_controller.rb +45 -0
- data/generators/sparkly/templates/sessions_helper.rb +2 -0
- data/generators/sparkly/templates/tasks/migrations.rb +1 -0
- data/generators/sparkly/templates/views/sparkly_accounts/edit.html.erb +24 -0
- data/generators/sparkly/templates/views/sparkly_accounts/new.html.erb +24 -0
- data/generators/sparkly/templates/views/sparkly_accounts/show.html.erb +0 -0
- data/generators/sparkly/templates/views/sparkly_sessions/new.html.erb +22 -0
- data/init.rb +44 -0
- data/lib/auth.rb +52 -0
- data/lib/auth/behavior/base.rb +64 -0
- data/lib/auth/behavior/core.rb +87 -0
- data/lib/auth/behavior/core/authenticated_model_methods.rb +52 -0
- data/lib/auth/behavior/core/controller_extensions.rb +52 -0
- data/lib/auth/behavior/core/controller_extensions/class_methods.rb +24 -0
- data/lib/auth/behavior/core/controller_extensions/current_user.rb +54 -0
- data/lib/auth/behavior/core/password_methods.rb +65 -0
- data/lib/auth/behavior/remember_me.rb +17 -0
- data/lib/auth/behavior/remember_me/configuration.rb +21 -0
- data/lib/auth/behavior/remember_me/controller_extensions.rb +66 -0
- data/lib/auth/behavior_lookup.rb +10 -0
- data/lib/auth/configuration.rb +328 -0
- data/lib/auth/encryptors/sha512.rb +20 -0
- data/lib/auth/generators/configuration_generator.rb +20 -0
- data/lib/auth/generators/controllers_generator.rb +34 -0
- data/lib/auth/generators/migration_generator.rb +32 -0
- data/lib/auth/generators/route_generator.rb +19 -0
- data/lib/auth/generators/views_generator.rb +26 -0
- data/lib/auth/model.rb +94 -0
- data/lib/auth/observer.rb +21 -0
- data/lib/auth/target_list.rb +5 -0
- data/lib/auth/tasks/migrations.rb +71 -0
- data/lib/auth/token.rb +10 -0
- data/lib/sparkly-auth.rb +1 -0
- data/rails/init.rb +17 -0
- data/rails/routes.rb +19 -0
- data/sparkly-auth.gemspec +143 -0
- data/spec/controllers/application_controller_spec.rb +13 -0
- data/spec/generators/sparkly_spec.rb +64 -0
- data/spec/lib/auth/behavior/core_spec.rb +184 -0
- data/spec/lib/auth/behavior/remember_me_spec.rb +127 -0
- data/spec/lib/auth/extensions/controller_spec.rb +32 -0
- data/spec/lib/auth/model_spec.rb +57 -0
- data/spec/lib/auth_spec.rb +32 -0
- data/spec/mocks/models/user.rb +3 -0
- data/spec/routes_spec.rb +24 -0
- data/spec/spec_helper.rb +61 -0
- data/spec/views_spec.rb +18 -0
- metadata +210 -0
@@ -0,0 +1,65 @@
|
|
1
|
+
class <%=model.accounts_controller.camelize%>Controller < SparklyController
|
2
|
+
require_login_for :show, :edit, :update, :destroy
|
3
|
+
|
4
|
+
# GET new_model_url
|
5
|
+
def new
|
6
|
+
end
|
7
|
+
|
8
|
+
# POST model_url
|
9
|
+
def create
|
10
|
+
if model.save
|
11
|
+
login!(model)
|
12
|
+
redirect_back_or_default Auth.default_destination, Auth.account_created_message
|
13
|
+
else
|
14
|
+
render :action => 'new'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# GET model_url
|
19
|
+
def show
|
20
|
+
end
|
21
|
+
|
22
|
+
# GET edit_model_url
|
23
|
+
def edit
|
24
|
+
end
|
25
|
+
|
26
|
+
# PUT model_url
|
27
|
+
def update
|
28
|
+
if !model_params[:password].blank? || !model_params[:password_confirmation].blank?
|
29
|
+
model.password = model_params[:password]
|
30
|
+
model.password_confirmation = model_params[:password_confirmation]
|
31
|
+
end
|
32
|
+
|
33
|
+
if model.save
|
34
|
+
redirect_back_or_default user_path, Auth.account_updated_message
|
35
|
+
else
|
36
|
+
render :action => 'edit'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# DELETE model_url
|
41
|
+
def destroy
|
42
|
+
current_user && current_user.destroy
|
43
|
+
logout!
|
44
|
+
@current_user = nil
|
45
|
+
flash[:notice] = Auth.account_deleted_message
|
46
|
+
redirect_back_or_default Auth.default_destination
|
47
|
+
end
|
48
|
+
|
49
|
+
protected
|
50
|
+
def find_user_model
|
51
|
+
# password fields are protected attrs, so we need to exclude them then add them explicitly.
|
52
|
+
self.model_instance = current_user ||
|
53
|
+
returning(model_class.new(model_params.without(:password, :password_confirmation))) { |model|
|
54
|
+
model.password = model_params[:password]
|
55
|
+
model.password_confirmation = model_params[:password_confirmation]
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
# Uncomment if you don't trust the params[:model] set up by Sparkly routing, or if you've
|
60
|
+
# disabled them.
|
61
|
+
#
|
62
|
+
#def model_name
|
63
|
+
# <%=model.name.inspect%>
|
64
|
+
#end
|
65
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
I'll assume you know what Sparkly Authentication is since it seems
|
2
|
+
to be installed. If that assumption is incorrect, you should check
|
3
|
+
out the Sparkly Authentication readme instead.
|
4
|
+
|
5
|
+
So let's get right into usage. This text was generated by the Sparkly
|
6
|
+
command-line generator, invoked via:
|
7
|
+
|
8
|
+
script/generate sparkly help
|
9
|
+
|
10
|
+
Depending on what arguments are attached, this generator is capable
|
11
|
+
of producing various different results. So let's go through them one
|
12
|
+
at a time, in the most common order...
|
13
|
+
|
14
|
+
0. Usually the first thing you'll want to do is generate the models
|
15
|
+
which will actually be authenticated, such as a User model. See
|
16
|
+
the Rails Guides for more details on that. You don't need to
|
17
|
+
actually run the migrations yet, however.
|
18
|
+
|
19
|
+
1. After you know which models will be authenticated, you're ready
|
20
|
+
to invoke the Sparkly Config generator:
|
21
|
+
|
22
|
+
script/generate sparkly config
|
23
|
+
|
24
|
+
This will generate a Rails Initializer in config/initializers that
|
25
|
+
will be used to set up Sparkly during runtime. This tells it what
|
26
|
+
encryption type to use, which models to authenticate, and so on.
|
27
|
+
You should take a look at this file to make sure the configuration
|
28
|
+
is what you are expecting. Do that. Now.
|
29
|
+
|
30
|
+
2. You also need to generate the database table which stores the
|
31
|
+
password information -- I'm talking about migrations!
|
32
|
+
|
33
|
+
script/generate sparkly migrations
|
34
|
+
|
35
|
+
4. Run the server and try it out. See how things feel. If you want
|
36
|
+
more control over the views (and you should), you can generate
|
37
|
+
them like so:
|
38
|
+
|
39
|
+
script/generate sparkly views
|
40
|
+
|
41
|
+
Their final resting place basically depends on what your Sparkly
|
42
|
+
config from Step 1 looks like. So I hope you double checked it.
|
43
|
+
|
44
|
+
5. Finally, if you need control over the, er, controllers, you can go
|
45
|
+
ahead and generate them like so:
|
46
|
+
|
47
|
+
script/generate sparkly controllers
|
48
|
+
|
49
|
+
Note that exactly which controllers and how many of them will be
|
50
|
+
generated depends, once again, on your Sparkly config. Note also
|
51
|
+
that this will generate the corresponding views for you, so you
|
52
|
+
can skip step 4 if you already know you need to customize the
|
53
|
+
controllers.
|
54
|
+
|
55
|
+
This file has been saved to doc/sparkly_authentication.txt for your
|
56
|
+
reference.
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# This file sets up Sparkly Auth to work properly with Rails. It was generated
|
2
|
+
# by "script/generate sparkly config" and can be regenerated with that command, though
|
3
|
+
# you may not want to actually do that if you've made changes to this file.
|
4
|
+
#
|
5
|
+
# You are also HIGHLY encouraged to check out the Auth::Configuration class documentation
|
6
|
+
# for a list of all the options you can set here. There are a LOT of them.
|
7
|
+
#
|
8
|
+
Auth.configure do |config|
|
9
|
+
config.authenticate :user
|
10
|
+
# Adds a model to be authenticated. See the Auth::Model class for information on
|
11
|
+
# what options you can pass. Here are some common examples:
|
12
|
+
#
|
13
|
+
# config.authenticate :user, :accounts_controller => "users", :sessions_controller => "user_sessions"
|
14
|
+
# config.authenticate :user, :key => "login"
|
15
|
+
#
|
16
|
+
# By default, :key is "email" and the controllers are Sparkly's internal controllers.
|
17
|
+
# (Don't forget you can also script/generate controllers or script/generate views to
|
18
|
+
# remove the overhead of setting up your own.)
|
19
|
+
#
|
20
|
+
|
21
|
+
# You can also configure the various behaviors (as long as they support configurations):
|
22
|
+
# config.remember_me.token_theft_message =
|
23
|
+
# "Your account may have been hijacked recently! Verify that all settings are correct."
|
24
|
+
#
|
25
|
+
# config.remember_me.duration = 6.months
|
26
|
+
#
|
27
|
+
# See the class documentation for the behaviors' configurations themselves for details
|
28
|
+
# about these options. (For example, see Auth::Behaviors::RememberMe::Configuration for
|
29
|
+
# the Remember Me configuration options.)
|
30
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class CreateSparklyPasswords < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :passwords do |t|
|
4
|
+
t.string :secret
|
5
|
+
t.string :salt
|
6
|
+
|
7
|
+
t.string :persistence_token # the token stored in cookies to persist the user's session
|
8
|
+
t.string :single_access_token # used to authenticate a user for a single request. This is not persisted.
|
9
|
+
t.string :perishable_token # used in confirming an account, usually via email
|
10
|
+
|
11
|
+
t.references :authenticatable, :polymorphic => true
|
12
|
+
t.timestamps
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.down
|
17
|
+
drop_table :passwords
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class CreateSparklyRememberedTokens < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :remembrance_tokens do |t|
|
4
|
+
t.string :series_token
|
5
|
+
t.string :remembrance_token
|
6
|
+
|
7
|
+
t.references :authenticatable, :polymorphic => true
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.down
|
13
|
+
drop_table :remembrance_tokens
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
class <%=model.sessions_controller.camelize%>Controller < SparklyController
|
2
|
+
# GET new_model_session_url
|
3
|
+
def new
|
4
|
+
end
|
5
|
+
|
6
|
+
# POST model_session_url
|
7
|
+
def create
|
8
|
+
if session[:locked_out_at] && session[:locked_out_at] > Auth.account_lock_duration.ago
|
9
|
+
flash[:error] = Auth.account_locked_message
|
10
|
+
render :action => 'new'
|
11
|
+
return
|
12
|
+
end
|
13
|
+
|
14
|
+
model = model_class.find(:first, :conditions => { model_config.key => model_params[model_config.key] },
|
15
|
+
:include => :passwords)
|
16
|
+
|
17
|
+
if model && model.password_matches?(model_params[:password])
|
18
|
+
login! model
|
19
|
+
redirect_back_or_default Auth.default_destination, Auth.login_successful_message
|
20
|
+
else
|
21
|
+
session[:login_failures] = session[:login_failures].to_i + 1
|
22
|
+
if Auth.max_login_failures && session[:login_failures] >= Auth.max_login_failures
|
23
|
+
session[:locked_out_at] = Time.now
|
24
|
+
flash[:error] = Auth.account_locked_message
|
25
|
+
else
|
26
|
+
flash[:error] = Auth.invalid_credentials_message
|
27
|
+
end
|
28
|
+
render :action => "new"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# DELETE model_session_url
|
33
|
+
def destroy
|
34
|
+
logout!
|
35
|
+
redirect_back_or_default Auth.default_destination, Auth.logout_message
|
36
|
+
end
|
37
|
+
|
38
|
+
protected
|
39
|
+
# Uncomment if you don't trust the params[:model] set up by Sparkly routing, or if you've
|
40
|
+
# disabled them.
|
41
|
+
#
|
42
|
+
#def model_name
|
43
|
+
# <%=model.name.inspect%>
|
44
|
+
#end
|
45
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'auth/tasks/migrations'
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<%form_for model, :url => model_path do |f|%>
|
2
|
+
<p>
|
3
|
+
<%=f.error_messages%>
|
4
|
+
</p>
|
5
|
+
|
6
|
+
<p>
|
7
|
+
<%=f.label model_config.key%><br/>
|
8
|
+
<%=f.text_field model_config.key%>
|
9
|
+
</p>
|
10
|
+
|
11
|
+
<p>
|
12
|
+
<%=f.label :password%><br/>
|
13
|
+
<%=f.password_field :password, :value => ''%>
|
14
|
+
</p>
|
15
|
+
|
16
|
+
<p>
|
17
|
+
<%=f.label :password_confirmation%><br/>
|
18
|
+
<%=f.password_field :password_confirmation, :value => ''%>
|
19
|
+
</p>
|
20
|
+
|
21
|
+
<p>
|
22
|
+
<%=f.submit "Update Profile"%>
|
23
|
+
</p>
|
24
|
+
<%end%>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<%form_for model, :url => model_path do |f|%>
|
2
|
+
<p>
|
3
|
+
<%=f.error_messages%>
|
4
|
+
</p>
|
5
|
+
|
6
|
+
<p>
|
7
|
+
<%=f.label model_config.key%><br/>
|
8
|
+
<%=f.text_field model_config.key%>
|
9
|
+
</p>
|
10
|
+
|
11
|
+
<p>
|
12
|
+
<%=f.label :password%><br/>
|
13
|
+
<%=f.password_field :password, :value => ''%>
|
14
|
+
</p>
|
15
|
+
|
16
|
+
<p>
|
17
|
+
<%=f.label :password_confirmation%><br/>
|
18
|
+
<%=f.password_field :password_confirmation, :value => ''%>
|
19
|
+
</p>
|
20
|
+
|
21
|
+
<p>
|
22
|
+
<%=f.submit "Sign up"%>
|
23
|
+
</p>
|
24
|
+
<%end%>
|
File without changes
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<%form_for model, :url => model_session_path do |f|%>
|
2
|
+
<p>
|
3
|
+
<%=f.label model_config.key%><br/>
|
4
|
+
<%=f.text_field model_config.key%>
|
5
|
+
</p>
|
6
|
+
|
7
|
+
<p>
|
8
|
+
<%=f.label :password%><br/>
|
9
|
+
<%=f.password_field :password, :value => ''%>
|
10
|
+
</p>
|
11
|
+
|
12
|
+
<%if Auth.remember_me.enabled?%>
|
13
|
+
<p>
|
14
|
+
<%=f.check_box :remember_me, :checked => false%>
|
15
|
+
<%=f.label :remember_me%>
|
16
|
+
</p>
|
17
|
+
<%end%>
|
18
|
+
|
19
|
+
<p>
|
20
|
+
<%=f.submit "Sign in"%>
|
21
|
+
</p>
|
22
|
+
<%end%>
|
data/init.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require File.expand_path("../dependencies", __FILE__)
|
2
|
+
require File.expand_path("../lib/auth", __FILE__)
|
3
|
+
|
4
|
+
$LOAD_PATH << Auth.path
|
5
|
+
ActiveSupport::Dependencies.load_paths << Auth.path
|
6
|
+
ActiveSupport::Dependencies.load_once_paths << Auth.path
|
7
|
+
#ActiveSupport::Dependencies.load_once_paths.delete(Auth.path)
|
8
|
+
|
9
|
+
# Kick auth after initialize and do it again before every request in development
|
10
|
+
Rails.configuration.to_prepare do
|
11
|
+
Auth.kick!
|
12
|
+
end
|
13
|
+
|
14
|
+
# FIXME HACK extension to ActiveRecord::Errors to allow error attributes to be renamed. This is
|
15
|
+
# because otherwise we'll end up producing very confusing error messages complaining about :secret,
|
16
|
+
# :encrypted_secret, and so forth when all the user really cares about is :password.
|
17
|
+
class ActiveRecord::Errors
|
18
|
+
def rename_attribute(original_name, new_name)
|
19
|
+
original_name, new_name = original_name.to_s, new_name.to_s
|
20
|
+
return if original_name == new_name
|
21
|
+
|
22
|
+
@errors.each do |attribute, old_errors|
|
23
|
+
if attribute.to_s == original_name
|
24
|
+
original_name = attribute # because some are strings, some are symbols.
|
25
|
+
|
26
|
+
old_errors.each do |error|
|
27
|
+
new_error = error.dup
|
28
|
+
new_error.attribute = new_name
|
29
|
+
unless @errors[new_name] && @errors[new_name].include?(new_error)
|
30
|
+
@errors[new_name] ||= []
|
31
|
+
@errors[new_name] << new_error
|
32
|
+
end
|
33
|
+
end
|
34
|
+
@errors.delete(original_name)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class ActiveRecord::Error
|
41
|
+
def ==(other)
|
42
|
+
other.kind_of?(ActiveRecord::Error) && attribute.to_s == other.attribute.to_s && message == other.message
|
43
|
+
end
|
44
|
+
end
|
data/lib/auth.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
module Auth
|
2
|
+
class << self
|
3
|
+
public :delegate
|
4
|
+
delegate :path, :encryptor, :default_accounts_controller_name, :default_sessions_controller_name,
|
5
|
+
:password_update_frequency, :base_controller, :login_required_message, :logout_required_message,
|
6
|
+
:default_destination, :session_duration, :invalid_credentials_message, :login_successful_message,
|
7
|
+
:logout_message, :session_timeout_message, :default_login_path, :account_deleted_message,
|
8
|
+
:account_created_message, :account_updated_message, :account_locked_message, :max_login_failures,
|
9
|
+
:generate_routes?, :disable_route_generation!, :password_uniqueness_message,
|
10
|
+
:password_history_length, :base_controller_name, :account_lock_duration,
|
11
|
+
:password_format, :password_format_message, :minimum_password_length, :behaviors, :behavior_classes,
|
12
|
+
:to => :configuration
|
13
|
+
|
14
|
+
def configuration
|
15
|
+
@configuration ||= Auth::Configuration.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def configure
|
19
|
+
yield configuration
|
20
|
+
end
|
21
|
+
|
22
|
+
# Applies all configuration settings. This is done by the Auth system after it has been configured but before
|
23
|
+
# it processes any requests.
|
24
|
+
def configure!
|
25
|
+
begin
|
26
|
+
configuration.apply!
|
27
|
+
rescue NameError
|
28
|
+
puts
|
29
|
+
puts "WARNING: #{$!.message}"
|
30
|
+
puts
|
31
|
+
puts "This happened while trying to configure Sparkly Authentication."
|
32
|
+
puts "You should verify that /config/initializers/sparkly_authentication.rb"
|
33
|
+
puts "is set up properly. It could be that you just haven't created the"
|
34
|
+
puts "model yet. If so, this error will disappear when the model exists."
|
35
|
+
puts
|
36
|
+
if ENV['AUTH_BACKTRACE']
|
37
|
+
puts $!.backtrace
|
38
|
+
else
|
39
|
+
puts "(Run with AUTH_BACKTRACE=true to see a full bactrace.)"
|
40
|
+
end
|
41
|
+
puts
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Useful for cleaning up after tests, but probably not much else.
|
46
|
+
def reset_configuration!
|
47
|
+
@configuration = Auth::Configuration.new
|
48
|
+
end
|
49
|
+
|
50
|
+
alias_method :kick!, :configure!
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
class Auth::Behavior::Base
|
2
|
+
class_inheritable_array :migrations
|
3
|
+
read_inheritable_attribute(:migrations) || write_inheritable_attribute(:migrations, [])
|
4
|
+
|
5
|
+
class << self
|
6
|
+
def apply_to_controllers
|
7
|
+
# Add additional methods to ApplicationController (or whatever controller Sparkly is told to use)
|
8
|
+
Auth.base_controller.send(:include, "#{name}::ControllerExtensions".constantize)
|
9
|
+
# why this doesn't work in cuke?
|
10
|
+
# if (container = self.class).const_defined?(:ControllerExtensions)
|
11
|
+
# Auth.base_controller.send(:include, container.const_get(:ControllerExtensions))
|
12
|
+
# end
|
13
|
+
#rescue NameError
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def apply_to(model)
|
18
|
+
track_behavior(model.target) do
|
19
|
+
apply_to_accounts(model)
|
20
|
+
apply_to_passwords(Password)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def apply_to_passwords(password_model)
|
25
|
+
raise NotImplementedError, "Be sure to override #apply_to_passwords(passwords_model) in your Auth Behavior"
|
26
|
+
end
|
27
|
+
|
28
|
+
def apply_to_accounts(model_config)
|
29
|
+
raise NotImplementedError, "Be sure to override #apply_to_accounts(model_config) in your Auth Behavior"
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
def track_behavior(model)
|
34
|
+
if !behavior_tracked?(model)
|
35
|
+
track_behavior!(model)
|
36
|
+
yield
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def behavior_tracked?(model)
|
41
|
+
behavior_tracker(model).include? behavior_name
|
42
|
+
end
|
43
|
+
|
44
|
+
def track_behavior!(model)
|
45
|
+
behavior_tracker(model) << behavior_name
|
46
|
+
end
|
47
|
+
|
48
|
+
def behavior_tracker(model)
|
49
|
+
model.instance_variable_get("@__behavior_tracker") || model.instance_variable_set("@__behavior_tracker", [])
|
50
|
+
end
|
51
|
+
|
52
|
+
def behavior_name
|
53
|
+
self.class.name
|
54
|
+
end
|
55
|
+
|
56
|
+
public
|
57
|
+
class << self
|
58
|
+
# Declares a migration template for a behavior. If sourcedir is given, it will be used as the location
|
59
|
+
# in which to find the template.
|
60
|
+
def migration(filename)
|
61
|
+
migrations << filename unless migrations.include?(filename)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|