Question

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

Était-ce utile?

La solution

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top