隐藏属性在ActiveRecord模型 [英] Hiding an attribute in an ActiveRecord model

查看:165
本文介绍了隐藏属性在ActiveRecord模型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有点新的Rails和工作设计使用ActiveRecord的用户模型。在此模型中,我有其目的是保持用户的密码的散列密码属性

I am somewhat new to Rails and working on designing a User model using ActiveRecord. In this model, I have a password attribute which is intended to keep a hash of the user's password.

我想直接删除这个属性的读取和设置。不过,我似乎无法找到一种方法,使用Rails的控制台时删除访问。唯一可行的解​​决方案,迄今已明确覆盖存取方法的密码,我真的不希望覆盖他们,我想访问了 - 或者至少是读

I want to remove both reading and setting of this attribute directly. However, I can't seem to find a way to remove the accessors when using the Rails console. The only viable solution so far has been to explicitly override the accessor methods for password and I don't really want to override them, I want the accessors gone - or at least the reader.

下面是我的模型:

class User < ActiveRecord::Base

  // various associations

  def password_correct?(password)
    read_attribute(:password) == hash(password)
  end

  def password=(password)
    write_attribute(:password, hash(password))
  end

  def password
    "get your dirty fingers off this attribute"
  end

  private

  def hash(input)
    Digest::SHA2.new(512).update(input).hexdigest
  end

end

任何想法如何做到这一点,或任何不足之处,以这种方式?

Any ideas how to achieve this or any shortcomings to this approach?

推荐答案

根据上面的答案,我也做了一些实验来获得期望的结果。最后我做一个私password_hash属性和虚拟的访问被称为密码。

Based on the above answers, I have done some experimentation to obtain the desired result. I ended up making a "private" password_hash attribute and a virtual accessor called password.

我在这个过程中做了一些意见:

I made some observations in this process:

  • 看来,ActiveRecord的不具有私人属性的任何概念。使私人使用的符号存取方法,如私人:密码:密码= 是不是一种选择,由于Rails引发 NameError:未定义的方法实例化模型时,由于模型本身没有定义这两个方法(它们似乎是从的ActiveRecord :: Base的继承)。

  • It seems that ActiveRecord doesn't have any concept of private attributes. Making the accessor methods private using symbols such as private :password, :password= is not an option, because Rails throws an NameError: undefined method when instantiating a model, as the model itself does not have these two methods defined (they seem to be inherited from ActiveRecord::Base).

重写password_hash访问纯没有什么是伟大的preventing属性的操作,但它也意味着,ActiveRecord的自身更新password_hash属性,因为它是调用空的实现时失败。

Overriding the password_hash accessors with pure nothing is great for preventing the manipulation of the attribute, however it also means that ActiveRecord itself fails when updating the password_hash attribute as it is calling an empty implementation.

所以使得访问私有失败,因为他们是不确定的,在实际的模型。定义他们也会失败,因为它打破ActiveRecord的。所以,你该怎么办?

So making the accessors private fails because they're undefined in the actual model. Defining them also fails, because it breaks ActiveRecord. So what can you do?

我做了两个和多一点。我做了访问私有的,定义他们,并通过调用实施两个。这$ P $由投掷 NoMethodError 访问这些pvents控制器(与铁轨控制台),但不拒绝ActiveRecord的。

I did both and a bit more. I made the accessors private, defined them and implemented both by calling super. This prevents the controller (and the rails console) from accessing them by throwing a NoMethodError, but doesn't reject ActiveRecord.

我用我的方法遇到的一个问题是打破验证。强制执行的password_hash的最小长度是没有好为任何密码(甚至没有)导致128字符SHA512哈希值。因此,验证哈希没有什么意义。相反,我加了验证,虚拟密码访问并增加了一个 before_save:hash_password 回调进行检查,看是否在虚拟访问属性已设置,如果是这样,散列它并将其写入到password_hash属性。

One problem I encountered with my approach was broken validation. Enforcing a minimum length on the password_hash was no good as any password (even nothing) results in a 128 character SHA512 hash. So validating the hash made little sense. Instead I added validation to the virtual password accessor and added a before_save :hash_password callback which checks to see if the virtual accessor attribute has been set and if so, hashes it and writes it to the password_hash attribute.

我的执行弄成这样:


class User < ActiveRecord::Base
  attr_accessible :first_name, :last_name, :email
  attr_accessor :password
  validates :password, :length => { :minimum => 8 }, :if => :password_changed?
  validates :first_name, :last_name, :email, presence: true
  // Various associations
  before_save :hash_password

  def password_correct?(p)
    if(password.present?)
      password == p
    else
    read_attribute(:password_hash) == hash_string(p)
    end
  end

  def role_symbols
    roles.collect do |r|
      r.name.to_sym
    end
  end

  private

  def hash_string(input)
    Digest::SHA2.new(512).update(input).hexdigest
  end

  def hash_password
    if(password.present?)
      write_attribute(:password_hash, hash_string(password))
      self.password = nil
    end
  end

  def password_changed?
    password.present? or new_record?
  end

  def password_hash
    super
  end

  def password_hash=(p)
    super
  end

end

这篇关于隐藏属性在ActiveRecord模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆