我试图修补ActiveRecord :: FinderMethods,以便为我的模型使用散列ID。例如,User.find(1)变为User.find(" FEW")。可悲的是,我的覆盖方法没有被调用。有关如何覆盖find_one方法的任何想法吗?
module ActiveRecord
module FinderMethods
alias_method :orig_find_one, :find_one
def find_one(id)
if id.is_a?(String)
orig_find_one decrypt_id(id)
else
orig_find_one(id)
end
end
end
end
答案 0 :(得分:1)
这篇文章讨论如何通过覆盖User.primary_key
方法来实际执行您想要的操作,如:
class User
self.primary_key = 'hashed_id'
end
允许您拨打User.find
并将其传递给“hashed_id”:
http://ruby-journal.com/how-to-override-default-primary-key-id-in-rails/
所以,这是可能的。
那就是说,我建议不要这样做,而是使用像User.find_by_hashed_id
这样的东西。唯一的区别是,当找不到结果而不是抛出nil
异常时,此方法将返回ActiveRecord::RecordNotFound
。你可以在控制器中手动抛出它:
def show
@user = User.find_by_hashed_id(hashed_id)
raise ActiveRecord::RecordNotFound.new if @user.nil?
... continue processing ...
end
最后,还有一个注意事项可以让你更容易--Rails还有一个方法可以覆盖你的模型to_param
,告诉它在生成路由时使用什么属性。当然,默认情况下,它使用id,但您可能希望使用hashed_id。
class User
def to_param
self.hashed_id
end
end
现在,在您的控制器中,params[:id]
将包含hashed_id而不是id。
def show
@user = User.find_by_hashed_id(params[:id])
raise ActiveRecord::RecordNotFound.new if @user.nil?
... continue processing ...
end
答案 1 :(得分:1)
我同意你这样做时应该小心,但这是可能的。
如果您有方法decode_id
将哈希ID转换回原始ID,则以下内容将起作用:
在User.rb
# Extend AR find method to allow finding records by an encoded string id:
def self.find(*ids)
return super if ids.length > 1
# Note the short-circuiting || to fall-back to default behavior
find_by(id: decode_id(ids[0])) || super
end
如果传递了无效的哈希值,请确保decode_id
返回nil。这样您可以通过Hashed ID和标准ID找到,因此如果您的用户ID为12345,则以下内容:
User.find(12345)
User.find("12345")
User.find(encode_id(12345))
所有人都应该返回同一个用户。