challah 1.1.1 → 1.2.0.rc

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -1
  3. data/README.md +3 -3
  4. data/app/models/authorization.rb +2 -2
  5. data/app/models/user.rb +2 -2
  6. data/lib/challah.rb +60 -53
  7. data/lib/challah/active_record_extensions.rb +23 -0
  8. data/lib/challah/{authorization.rb → concerns/authorizeable.rb} +14 -19
  9. data/lib/challah/concerns/user/attributeable.rb +73 -0
  10. data/lib/challah/{user/authentication.rb → concerns/user/authenticateable.rb} +2 -2
  11. data/lib/challah/concerns/user/authorizable.rb +32 -0
  12. data/lib/challah/concerns/user/findable.rb +45 -0
  13. data/lib/challah/{user/password.rb → concerns/user/passwordable.rb} +2 -2
  14. data/lib/challah/{user/providers.rb → concerns/user/provideable.rb} +46 -6
  15. data/lib/challah/concerns/user/validateable.rb +21 -0
  16. data/lib/challah/concerns/userable.rb +20 -0
  17. data/lib/challah/engine.rb +1 -2
  18. data/lib/challah/test.rb +52 -32
  19. data/lib/challah/version.rb +1 -1
  20. metadata +14 -76
  21. data/lib/challah/user.rb +0 -128
  22. data/lib/challah/user/attributes.rb +0 -28
  23. data/lib/challah/user/finders.rb +0 -31
  24. data/lib/challah/user/reflector.rb +0 -15
  25. data/test/controllers/controller_test.rb +0 -34
  26. data/test/controllers/restrictions_controller_test.rb +0 -95
  27. data/test/controllers/sessions_controller_test.rb +0 -42
  28. data/test/dummy/README.rdoc +0 -28
  29. data/test/dummy/Rakefile +0 -6
  30. data/test/dummy/app/assets/javascripts/application.js +0 -13
  31. data/test/dummy/app/assets/stylesheets/application.css +0 -13
  32. data/test/dummy/app/controllers/application_controller.rb +0 -5
  33. data/test/dummy/app/controllers/restrictions_controller.rb +0 -25
  34. data/test/dummy/app/helpers/application_helper.rb +0 -2
  35. data/test/dummy/app/models/user.rb +0 -15
  36. data/test/dummy/app/models/widget.rb +0 -3
  37. data/test/dummy/app/views/bakery/templates/layouts/sample.erb +0 -1
  38. data/test/dummy/app/views/bakery/templates/partials/sample.html.haml +0 -1
  39. data/test/dummy/app/views/bakery/templates/themes/sample.haml +0 -1
  40. data/test/dummy/app/views/layouts/application.html.erb +0 -14
  41. data/test/dummy/config.ru +0 -4
  42. data/test/dummy/config/application.rb +0 -24
  43. data/test/dummy/config/boot.rb +0 -5
  44. data/test/dummy/config/database.yml +0 -30
  45. data/test/dummy/config/environment.rb +0 -5
  46. data/test/dummy/config/environments/development.rb +0 -29
  47. data/test/dummy/config/environments/production.rb +0 -80
  48. data/test/dummy/config/environments/test.rb +0 -36
  49. data/test/dummy/config/initializers/backtrace_silencers.rb +0 -7
  50. data/test/dummy/config/initializers/filter_parameter_logging.rb +0 -4
  51. data/test/dummy/config/initializers/i18n.rb +0 -1
  52. data/test/dummy/config/initializers/inflections.rb +0 -16
  53. data/test/dummy/config/initializers/mime_types.rb +0 -5
  54. data/test/dummy/config/initializers/secret_token.rb +0 -12
  55. data/test/dummy/config/initializers/session_store.rb +0 -3
  56. data/test/dummy/config/initializers/wrap_parameters.rb +0 -14
  57. data/test/dummy/config/locales/en.yml +0 -23
  58. data/test/dummy/config/routes.rb +0 -5
  59. data/test/dummy/db/migrate/20140114212939_create_widgets.rb +0 -32
  60. data/test/dummy/db/migrate/20140307205735_create_users.challah_engine.rb +0 -34
  61. data/test/dummy/db/migrate/20140307205736_create_authorizations.challah_engine.rb +0 -21
  62. data/test/dummy/db/schema.rb +0 -81
  63. data/test/dummy/db/test.sqlite3 +0 -0
  64. data/test/dummy/log/test.log +0 -11547
  65. data/test/dummy/public/404.html +0 -58
  66. data/test/dummy/public/422.html +0 -58
  67. data/test/dummy/public/500.html +0 -57
  68. data/test/dummy/public/favicon.ico +0 -0
  69. data/test/dummy/tmp/cache/assets/test/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
  70. data/test/dummy/tmp/cache/assets/test/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
  71. data/test/dummy/tmp/cache/assets/test/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
  72. data/test/dummy/tmp/cache/assets/test/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
  73. data/test/dummy/tmp/cache/assets/test/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
  74. data/test/dummy/tmp/cache/assets/test/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
  75. data/test/factories.rb +0 -8
  76. data/test/models/authorization_test.rb +0 -20
  77. data/test/models/user_test.rb +0 -345
  78. data/test/services/audit_test.rb +0 -107
  79. data/test/services/cookie_store_test.rb +0 -97
  80. data/test/services/encrypter_test.rb +0 -73
  81. data/test/services/plugins_test.rb +0 -65
  82. data/test/services/random_test.rb +0 -22
  83. data/test/services/routes_test.rb +0 -11
  84. data/test/services/session_test.rb +0 -197
  85. data/test/services/signup_test.rb +0 -122
  86. data/test/services/simple_cookie_store_test.rb +0 -122
  87. data/test/support/stubs.rb +0 -88
  88. data/test/test_helper.rb +0 -47
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a04a0045083c40526c41b4bb5e55606a99fb380c
4
- data.tar.gz: 192237d8884a972ac4a9fcdc97bf413814d8a378
3
+ metadata.gz: 7f5f10d1f9752cdc2f931499b2fe600a8ba6486a
4
+ data.tar.gz: b017bd1018d5e4cebe7d21074d718c0d41653eab
5
5
  SHA512:
6
- metadata.gz: 99461c5009e3db27fa353fb0abb551b1a25e0012c0622144f5c1a9f45fc30334e651c8820d8efdfc423021407a9aa809f90b238d3ff0b32ace267f7c63e63bdf
7
- data.tar.gz: a5b91063515c94e25d33189fbaa94866e66592eadcbd50cbc5459267ab499145f83c5b6366c259367348f0dc2c1903635e8891e5ad275cb66ff6368427f125f4
6
+ metadata.gz: f6a938dda2a821281f14832ba8225f5e3a711bec8b2fe8e62eae2564304d214d4dd78fd36e192cea36ff90abda58fbc002bb78b071a2fa9fb25fdf065a8b3ade
7
+ data.tar.gz: d73118e85864d9112c865b926b69e35324ee489ce7aa55ee667c3222d198d538b6bc2a204fb59daf22beef4c01d7b4f5726f6b3f54888fe1143dd78476ac4317
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ ## Challah (Not Released)
2
+
3
+ * Convert tests to RSpec
4
+ * Remove use of `challah_user` and replace with concerns
5
+ * Internal clean up of included modules
6
+
7
+ ## Challah 1.1.1
8
+
9
+ * Internal clean up of tests and gem dependencies
10
+ * Enable compatibility with Rails 4.1.0.rc1
11
+
1
12
  ## Challah 1.1.0
2
13
 
3
14
  * Allow challah to authenticate with User and Authorization tables that using namespaces
@@ -131,4 +142,4 @@
131
142
 
132
143
  ## Challah 0.2.0
133
144
 
134
- * Initial build. Basic functionality for session persistence and authentication.
145
+ * Initial build. Basic functionality for session persistence and authentication.
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Challah
2
2
 
3
- [![Build Status](https://secure.travis-ci.org/jdtornow/challah.png)](http://travis-ci.org/jdtornow/challah) [![Dependency Status](https://gemnasium.com/jdtornow/challah.png?travis)](https://gemnasium.com/jdtornow/challah)
3
+ [![Build Status](https://secure.travis-ci.org/jdtornow/challah.png)](http://travis-ci.org/jdtornow/challah) [![Code Climate](https://codeclimate.com/github/jdtornow/challah.png)](https://codeclimate.com/github/jdtornow/challah) [![Dependency Status](https://gemnasium.com/jdtornow/challah.png?travis)](https://gemnasium.com/jdtornow/challah) [![Gem Version](https://badge.fury.io/rb/challah.png)](http://badge.fury.io/rb/challah)
4
4
 
5
5
  Challah (pronounced HAH-lah) is a simple Rails authentication gem that provides users a way to authenticate with your app. Most of the functionality within the gem lives within a Rails engine and tries to stay out of the way of your app.
6
6
 
@@ -144,9 +144,9 @@ If you have any issues or find bugs running Challah, please [report them on Gith
144
144
 
145
145
  ### Testing
146
146
 
147
- Challah is fully tested using Test Unit, Shoulda and Mocha. To run the test suite, `bundle install` then run:
147
+ Challah is fully tested using RSpec. To run the test suite, `bundle install` then run:
148
148
 
149
- rake test
149
+ rspec
150
150
 
151
151
  ## License
152
152
 
@@ -1,3 +1,3 @@
1
1
  class Authorization < ActiveRecord::Base
2
- challah_authorization
3
- end
2
+ include Challah::Authorizeable
3
+ end
data/app/models/user.rb CHANGED
@@ -11,5 +11,5 @@ class User < ActiveRecord::Base
11
11
  # For a list of all methods included into User, see:
12
12
  #
13
13
  # http://rubydoc.info/gems/challah
14
- challah_user
15
- end
14
+ include Challah::Userable
15
+ end
data/lib/challah.rb CHANGED
@@ -1,59 +1,66 @@
1
- require 'challah/version'
1
+ require "challah/version"
2
2
 
3
3
  module Challah
4
- autoload :Audit, 'challah/audit'
5
-
6
- autoload :CookieStore, 'challah/cookie_store'
7
- autoload :SimpleCookieStore, 'challah/simple_cookie_store'
8
-
9
- autoload :Authenticators, 'challah/authenticators'
10
- autoload :Controller, 'challah/controller'
11
- autoload :Encrypter, 'challah/encrypter'
12
- autoload :Plugins, 'challah/plugins'
13
- autoload :Providers, 'challah/providers'
14
- autoload :Random, 'challah/random'
15
- autoload :Session, 'challah/session'
16
- autoload :Signup, 'challah/signup'
17
- autoload :Techniques, 'challah/techniques'
18
- autoload :Techniques, 'challah/techniques'
19
-
20
- autoload :EmailValidator, 'challah/validators/email_validator'
21
- autoload :PasswordValidator, 'challah/validators/password_validator'
22
-
23
- autoload :Authorization, 'challah/authorization'
24
- autoload :User, 'challah/user'
25
-
26
- autoload :PasswordProvider, 'challah/providers/password_provider'
4
+ autoload :Audit, "challah/audit"
5
+
6
+ autoload :CookieStore, "challah/cookie_store"
7
+ autoload :SimpleCookieStore, "challah/simple_cookie_store"
8
+
9
+ autoload :Authenticators, "challah/authenticators"
10
+ autoload :Controller, "challah/controller"
11
+ autoload :Encrypter, "challah/encrypter"
12
+ autoload :Plugins, "challah/plugins"
13
+ autoload :Providers, "challah/providers"
14
+ autoload :Random, "challah/random"
15
+ autoload :Session, "challah/session"
16
+ autoload :Signup, "challah/signup"
17
+ autoload :Techniques, "challah/techniques"
18
+ autoload :Techniques, "challah/techniques"
19
+
20
+ autoload :EmailValidator, "challah/validators/email_validator"
21
+ autoload :PasswordValidator, "challah/validators/password_validator"
22
+
23
+ autoload :PasswordProvider, "challah/providers/password_provider"
24
+
25
+ autoload :ActiveRecordExtensions, "challah/active_record_extensions"
26
+
27
+ autoload :Authorizeable, "challah/concerns/authorizeable"
28
+ autoload :Userable, "challah/concerns/userable"
29
+ autoload :UserAttributeable, "challah/concerns/user/attributeable"
30
+ autoload :UserAuthenticateable, "challah/concerns/user/authenticateable"
31
+ autoload :UserAuthorizable, "challah/concerns/user/authorizable"
32
+ autoload :UserFindable, "challah/concerns/user/findable"
33
+ autoload :UserPasswordable, "challah/concerns/user/passwordable"
34
+ autoload :UserProvideable, "challah/concerns/user/provideable"
35
+ autoload :UserValidateable, "challah/concerns/user/validateable"
27
36
 
28
37
  # Configuration options
29
- class << self
30
- # Get or set options for the current Challah instance. In most cases these should be
31
- # changed within a config/initializers/ file in your app.
32
- #
33
- # @param [Hash] options The options to get or set
34
- # @option options [String] :cookie_prefix ('challah') A prefix to put in the names of the cookies that will be set.
35
- # @option options [String] :access_denied_view ('challah/sessions/access_denied')Relative path to the view that will be used to show access denied method.
36
- # @option options [Class] :storage_class (SimpleCookieStore) The class to use for persistence of sessions.
37
- # @option options [Boolean] :skip_routes (false) Pass in true to not add any routes into your Rails app by default.
38
- # @option options [String] :email_validator ('challah/email') Pass in a string name of the class to use for email validation. Class should inherit from ActiveModel::EachValidator
39
- # @option options [Class] :password_validator (Challah::PasswordValidator) Pass in a class to use for password validation.
40
- def options
41
- @options ||= {
42
- access_denied_view: 'sessions/access_denied',
43
- api_key_enabled: false,
44
- cookie_prefix: 'challah',
45
- email_validator: 'challah/email',
46
- password_validator: PasswordValidator,
47
- skip_routes: false,
48
- skip_user_validations: false,
49
- storage_class: SimpleCookieStore,
50
- user: :User
51
- }
52
- end
53
-
54
- def user
55
- @user ||= options[:user].to_s.safe_constantize
56
- end
38
+ # Get or set options for the current Challah instance. In most cases these should be
39
+ # changed within a config/initializers/ file in your app.
40
+ #
41
+ # @param [Hash] options The options to get or set
42
+ # @option options [String] :cookie_prefix ("challah") A prefix to put in the names of the cookies that will be set.
43
+ # @option options [String] :access_denied_view ("challah/sessions/access_denied")Relative path to the view that will be used to show access denied method.
44
+ # @option options [Class] :storage_class (SimpleCookieStore) The class to use for persistence of sessions.
45
+ # @option options [Boolean] :skip_routes (false) Pass in true to not add any routes into your Rails app by default.
46
+ # @option options [String] :email_validator ("challah/email") Pass in a string name of the class to use for email validation. Class should inherit from ActiveModel::EachValidator
47
+ # @option options [Class] :password_validator (Challah::PasswordValidator) Pass in a class to use for password validation.
48
+ def self.options
49
+ @options ||= {
50
+ access_denied_view: "sessions/access_denied",
51
+ api_key_enabled: false,
52
+ cookie_prefix: "challah",
53
+ email_validator: "challah/email",
54
+ password_validator: PasswordValidator,
55
+ skip_routes: false,
56
+ skip_user_validations: false,
57
+ storage_class: SimpleCookieStore,
58
+ user: :User
59
+ }
60
+ end
61
+
62
+ def self.user
63
+ @user ||= options[:user].to_s.safe_constantize
57
64
  end
58
65
 
59
66
  # Set up techniques engines
@@ -83,4 +90,4 @@ module Challah
83
90
  register_provider :password, PasswordProvider
84
91
  end
85
92
 
86
- require 'challah/engine' if defined?(Rails)
93
+ require "challah/engine" if defined?(Rails)
@@ -0,0 +1,23 @@
1
+ module Challah
2
+ # Included for backwards compatibility. These methods are deprecated
3
+ # and will be removed in future versions
4
+ module ActiveRecordExtensions
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ extend ClassMethods
9
+ end
10
+
11
+ module ClassMethods
12
+ def challah_authorization
13
+ ActiveSupport::Deprecation.warn("#{ self.to_s }.challah_authorization is deprecated and will be removed in future versions, use `include Challah::Authorizeable` instead")
14
+ self.send(:include, Challah::Authorizeable)
15
+ end
16
+
17
+ def challah_user
18
+ ActiveSupport::Deprecation.warn("#{ self.to_s }.challah_user is deprecated and will be removed in future versions, use `include Challah::Userable` instead")
19
+ self.send(:include, Challah::Userable)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,18 +1,14 @@
1
1
  module Challah
2
- module Authorization
2
+ module Authorizeable
3
+ extend ActiveSupport::Concern
3
4
 
4
- def challah_authorization
5
- unless included_modules.include?(InstanceMethods)
6
- include InstanceMethods
7
- extend ClassMethods
8
- end
5
+ included do
6
+ extend ClassMethods
9
7
  end
10
8
 
11
- module InstanceMethods
12
- def user
13
- return nil unless self.user_id
14
- @user ||= self.class.user_model.where(id: self.user_id).first
15
- end
9
+ def user
10
+ return nil unless self.user_id
11
+ @user ||= self.class.user_model.where(id: self.user_id).first
16
12
  end
17
13
 
18
14
  module ClassMethods
@@ -59,15 +55,14 @@ module Challah
59
55
  record.save!
60
56
  record
61
57
  end
62
- end
63
58
 
64
- def users_table_name
65
- @users_table_name ||= user_model.table_name
66
- end
59
+ def users_table_name
60
+ @users_table_name ||= user_model.table_name
61
+ end
67
62
 
68
- def user_model
69
- @user_model ||= Challah.user
63
+ def user_model
64
+ @user_model ||= Challah.user
65
+ end
70
66
  end
71
-
72
67
  end
73
- end
68
+ end
@@ -0,0 +1,73 @@
1
+ module Challah
2
+ module UserAttributeable
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ attr_reader :password
7
+ attr_reader :password_confirmation
8
+ attr_reader :password_updated
9
+
10
+ before_save :ensure_user_tokens
11
+ end
12
+
13
+ # Returns true if this user is active, and should be able to log in. If
14
+ # the active column is false, the user will not be able to authenticate
15
+ def active?
16
+ !!self.active
17
+ end
18
+
19
+ # First name and last name together
20
+ def name
21
+ "#{ first_name } #{ last_name }".strip
22
+ end
23
+
24
+ # shortened name, just includes the first name and last initial
25
+ def small_name
26
+ "#{ first_name.to_s.titleize } #{ last_name.to_s.first.upcase }."
27
+ end
28
+
29
+ # Is this user valid and ready for a user session?
30
+ #
31
+ # Override this method if you need to check for a particular configuration on each page request.
32
+ def valid_session?
33
+ self.active?
34
+ end
35
+
36
+ protected
37
+
38
+ # Ensure that all system-generated columns aren't blank on each save
39
+ def ensure_user_tokens
40
+ ensure_api_key_presence
41
+ ensure_email_hash_presence
42
+ ensure_persistence_token_presence
43
+ end
44
+
45
+ # Store a random seed for this user's api key
46
+ def ensure_api_key_presence
47
+ if respond_to?("api_key=")
48
+ if self.api_key.to_s.blank?
49
+ self.api_key = Random.token(50)
50
+ end
51
+ end
52
+ end
53
+
54
+ # Store a hashed email if the column exists
55
+ def ensure_email_hash_presence
56
+ if respond_to?("email_hash=")
57
+ if email_changed?
58
+ self.email_hash = Encrypter.md5(email.to_s.downcase.strip)
59
+ end
60
+ end
61
+ end
62
+
63
+ # Store a random token to identify user in persisted objects
64
+ def ensure_persistence_token_presence
65
+ if respond_to?("persistence_token=")
66
+ if self.persistence_token.to_s.blank?
67
+ self.persistence_token = Random.token(125)
68
+ end
69
+ end
70
+ end
71
+
72
+ end
73
+ end
@@ -1,5 +1,5 @@
1
- module Challah::User
2
- module Authentication
1
+ module Challah
2
+ module UserAuthenticateable
3
3
  # Generic authentication method. By default, this just checks to see if the password
4
4
  # given matches this user. You can also pass in the first parameter as the method
5
5
  # to use for a different type of authentication.
@@ -0,0 +1,32 @@
1
+ module Challah
2
+ module UserAuthorizable
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ extend ClassMethods
7
+
8
+ before_destroy :clear_authorizations_before_destroy
9
+ end
10
+
11
+ protected
12
+
13
+ def authorizations
14
+ return [] if new_record?
15
+ self.class.authorization_model.where(user_id: self.id)
16
+ end
17
+
18
+ def clear_authorizations_before_destroy
19
+ authorizations.destroy_all
20
+ end
21
+
22
+ module ClassMethods
23
+ def authorizations_table_name
24
+ @authorizations_table_name ||= authorization_model.table_name
25
+ end
26
+
27
+ def authorization_model
28
+ @authorization_model ||= ::Authorization
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,45 @@
1
+ module Challah
2
+ module UserFindable
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ extend ClassMethods
7
+ end
8
+
9
+ module ClassMethods
10
+ def active
11
+ where(active: true)
12
+ end
13
+
14
+ # Find a user instance by username first, or email address if needed.
15
+ # If no user is found matching, return nil
16
+ def find_for_session(username_or_email)
17
+ return nil if username_or_email.to_s.blank?
18
+
19
+ result = nil
20
+
21
+ if username_or_email.to_s.include?('@')
22
+ result = where(email: username_or_email).first
23
+ end
24
+
25
+ if !result
26
+ uid = username_or_email.to_s.downcase.strip
27
+
28
+ authorization = self.authorization_model
29
+ authorization = authorization.where(provider: :password, uid: uid)
30
+ authorization = authorization.first
31
+
32
+ if authorization
33
+ result = authorization.user
34
+ end
35
+ end
36
+
37
+ result
38
+ end
39
+
40
+ def inactive
41
+ where.not(active: true)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -1,5 +1,5 @@
1
- module Challah::User
2
- module Password
1
+ module Challah
2
+ module UserPasswordable
3
3
  # Set the password and password_confirmation in one shortcut method.
4
4
  def password!(new_password)
5
5
  self.password = new_password
@@ -1,9 +1,22 @@
1
- module Challah::User
2
- module Providers
1
+ module Challah
2
+ module UserProvideable
3
+ extend ActiveSupport::Concern
3
4
 
4
- def authorizations
5
- return [] if new_record?
6
- self.class.authorization_model.where(user_id: self.id)
5
+ included do
6
+ after_save :update_modified_providers_after_save
7
+ after_save :clear_cached_providers_after_save
8
+ end
9
+
10
+ def method_missing(method, *args)
11
+ method_name = method.to_s
12
+
13
+ if method_name =~ /^([a-z]*)_provider\?$/
14
+ return provider?($1)
15
+ elsif method_name =~ /^([a-z]*)_provider$/
16
+ return provider($1)
17
+ end
18
+
19
+ super
7
20
  end
8
21
 
9
22
  def providers
@@ -60,6 +73,33 @@ module Challah::User
60
73
  false
61
74
  end
62
75
  end
63
- end
64
76
 
77
+ protected
78
+
79
+ def clear_cached_providers_after_save
80
+ @providers = nil
81
+ end
82
+
83
+ # If password or username was changed, update the authorization record
84
+ def update_modified_providers_after_save
85
+ # Save password provider
86
+ if @password_updated or @username_updated
87
+ Challah.providers[:password].save(self)
88
+ @password_updated = false
89
+ @username_updated = false
90
+ @password = nil
91
+ end
92
+
93
+ # Save any other providers
94
+ Challah.custom_providers.each do |name, klass|
95
+ custom_provider_attributes = provider_attributes[name]
96
+
97
+ if custom_provider_attributes.respond_to?(:fetch)
98
+ if klass.valid?(self)
99
+ klass.save(self)
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
65
105
  end