Rails SRP Modules, attr_accessible
题
I'm learning SOLID and trying to introduce SRP into my rails app. I have the following user model with basic authentication:
class User < ActiveRecord::Base
attr_accessible :password, :password_confirmation
attr_accessor :password
before_save :encrypt_password
validates_confirmation_of :password
validates_presence_of :password, :on => :create
def self.authenticate(email, password)
user = find_by_email(email)
if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)
user
else
nil
end
end
def encrypt_password
if password.present?
self.password_salt = BCrypt::Engine.generate_salt
self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)
end
end
def self.generate_random_password
return ActiveSupport::SecureRandom.hex(12)
end
end
I want to move all the authentication logic to a module like so:
module Authentication
attr_accessible :password, :password_confirmation
attr_accessor :password
before_save :encrypt_password
validates_confirmation_of :password
validates_presence_of :password, :on => :create
def self.authenticate(email, password)
user = find_by_email(email)
if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)
user
else
nil
end
end
def encrypt_password
if password.present?
self.password_salt = BCrypt::Engine.generate_salt
self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)
end
end
def self.generate_random_password
return ActiveSupport::SecureRandom.hex(12)
end
end
And my user model would be like this:
class User < ActiveRecord::Base
include Authentication #SRP in action! :P
end
And now the errors begin:
undefined method `attr_accessible' for Authentication:Module
How would I fix this error? I am convinced this is the best start to introduce SRP to my Rails app.
Thanks
解决方案
The attr_accessible method is called in the wrong scope. Take a look at Concerns to fix this:
http://api.rubyonrails.org/classes/ActiveSupport/Concern.html
This would result in:
module Authentication
extend ActiveSupport::Concern
included do
attr_accessible :password, :password_confirmation
end
...
end
This will also take care of you class and instance method definitions.
NOTE: To be specific, this does not quite achieve SRP, since multiple responsibilities are still shared within the same class, even though they are separated into modules. Class composition through referencing or decorating would be a more strict solution , but I prefer the pragmatic approach of modules.