隐藏属性在ActiveRecord模型 [英] Hiding an attribute in an ActiveRecord model
问题描述
我有点新的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 anNameError: undefined method
when instantiating a model, as the model itself does not have these two methods defined (they seem to be inherited fromActiveRecord::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屋!