【问题标题】:Devise + Legacy DB: "password" columnDevise + Legacy DB:“密码”列
【发布时间】:2014-02-24 16:34:19
【问题描述】:

我正在尝试将一个旧的 CakePHP 站点慢慢迁移到 Rails 4。由于需要大量工作,该站点需要逐步迁移,一次只迁移一个,并从 Active Admin 开始。我已经看到很多关于做这样的事情的问题,但是我需要考虑一些棘手的额外事情:

  1. 我无法修改 CakePHP 代码
  2. 我无法破坏 CakePHP 网站
  3. CakePHP 站点将其散列密码存储在名为“password”的数据库列中,而 Devise 不喜欢这样。它希望“password”是明文密码,并且已经养成了试图覆盖该 DB 列的坏习惯。

一旦整个站点迁移到 Rails,我当然可以开始关注关于如何将应用程序迁移到 Devise 的无数答案中的任何一个,但现在我需要工作 与现有的应用程序

谢谢

【问题讨论】:

    标签: ruby-on-rails ruby devise ruby-on-rails-4 legacy-database


    【解决方案1】:

    我发现了这个:http://www.slideshare.net/napcs/rails-and-legacy-databases-railsconf-2009,并按照他的建议创建了 sql 视图来包装遗留表。

    这是我以前在我的上运行的(我在 Limesurvey 上添加了一个应用程序):

    CREATE VIEW `users` AS
    SELECT `uid` as `id`,
           `users_name` as `username`,
           `email` as `email`,
           `password` as `encrypted_password`,
           `full_name` as `full_name`,
           `role_names` as `role_names`,
           `parent_id` as `parent_id`,
           `lang` as `lang`,
           `one_time_pw` as `one_time_pw`,
           `created` as `created_at`,
           `modified` as `updated_at`
    FROM `lime_users`;"
    

    问题是您必须在 sql 视图中包含基表中没有默认值的所有列,以便您插入到视图中。这是将“丑陋”的列名规范化为 Rails 友好的列名的好方法。

    我的用户模型:

    class User < ActiveRecord::Base
      before_save :save_encrypted_password
      self.primary_key = "id" # This needs to be declared, for some reason.
    
      def sha2(password)
        (Digest::SHA2.new << password).to_s
      end
    
      def valid_password?(password)
        return false if encrypted_password.blank?
        return Devise.secure_compare(sha2(password), self.encrypted_password)
      end
    protected
      def save_encrypted_password
        if password == password_confirmation
          self.encrypted_password = sha2(password)
        else
          errors.add :password_confirmation, "has to match password"
        end
      end
    end
    

    在数据库中的模型约束(非空值、唯一值等)中进行反映也是一个好主意,以避免更多的陷阱。 (经过近一个小时的艰辛阅读奥秘的错误消息后,才学会了这一点。)

    希望这会有所帮助。

    【讨论】:

      【解决方案2】:

      我能够通过安装可忽略的 gem 并在默认范围内选择密码列 AS encrypted_pa​​ssword 来解决此问题。这很丑,但它有效

      class User < ActiveRecord::Base
        ignore_columns :password
      
        default_scope :select => "#{User.quoted_table_name}.*, #{User.quoted_table_name}.password AS encrypted_password"
      
        devise :database_authenticatable
      
        def valid_password?(password)
          hash = ::Digest::MD5.hexdigest("[SALT REDACTED]#{password}").downcase
          return hash == self.encrypted_password
        end
      end
      

      【讨论】:

      • 我的情况与您的情况相同(现有的 PHP 应用程序),我希望我能早点看到这一点。在过去的一个小时里,我环顾四周,甚至查看了 Devise 源代码并在我的代码中添加断点以进行调试,最后才想起 Devise 添加了一个名为 password 的虚拟属性,它覆盖了我的数据库密码。
      • 我感受到了你的痛苦。我正在尝试开发一种宝石来帮助解决这种问题。如果您提出任何其他奇怪的问题,我很乐意听到。
      • 不幸的是,default_scope 具有改变关系调用的副作用(例如角色 habtm 用户,调用 role.user_ids 会返回所有内容,而不仅仅是用户的 ID)。我正在通过重新声明 role.user_ids 以仅返回 ID 来解决它。
      猜你喜欢
      • 1970-01-01
      • 2011-07-30
      • 2012-09-23
      • 1970-01-01
      • 2015-10-07
      • 2015-11-20
      • 2017-04-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多