6

いくつかのモデルの設計をリファクタリングしたい状況に何度か遭遇し、最終的に更新ロジックを移行に入れました。ただし、私が理解している限り、これは適切な方法ではありません (特に、移行ではなく展開にスキーマ ファイルを使用することが推奨されているため)。このような問題にどのように対処しますか?

言いたいことを明確にするために、User モデルがあるとします。ユーザーには「通常の」ユーザーと管理者の 2 種類しかないと思っていたので、ユーザーが管理者かどうかを示す単純なブール値フィールドを使用することにしました。

しかし、しばらくして、モデレーターなどの第 3 の種類のユーザーが必要であると考えました。この場合、UserType モデル (および対応する移行) を追加し、ユーザー テーブルから "admin" フラグを削除するための 2 番目の移行を追加します。そして、ここで問題が発生します。「add_user_type_to_users」移行では、管理フラグの値をユーザー タイプにマップする必要があります。さらに、これを行うには、ユーザー タイプが存在する必要があります。つまり、シード ファイルを使用できず、移行でユーザー タイプを作成する必要があります (これも悪い習慣と見なされます)。状況を表す架空のコードを次に示します。

class CreateUserTypes < ActiveRecord::Migration
    def self.up
        create_table :user_types do |t|
            t.string :name, :nil => false, :unique => true
        end

        #Create basic types (can not put in seed, because of future migration dependency)
        UserType.create!(:name => "BASIC")
        UserType.create!(:name => "MODERATOR")
        UserType.create!(:name => "ADMINISTRATOR")
    end

    def self.down
        drop_table :user_types
    end
end

class AddTypeIdToUsers < ActiveRecord::Migration
    def self.up
        add_column :users, :type_id, :integer

        #Determine type via the admin flag
        basic = UserType.find_by_name("BASIC")
        admin = UserType.find_by_name("ADMINISTRATOR")
        User.all.each {|u| u.update_attribute(:type_id, (u.admin?) ? admin.id : basic.id)}

        #Remove the admin flag
        remove_column :users, :admin

        #Add foreign key
        execute "alter table users add constraint fk_user_type_id
            foreign key (type_id) references user_types (id)"
    end

    def self.down
        #Re-add the admin flag
        add_column :users, :admin, :boolean, :default => false

        #Reset the admin flag (this is the problematic update code)
        admin = UserType.find_by_name("ADMINISTRATOR")

        execute "update users set admin=true where type_id=#{admin.id}"

        #Remove foreign key constraint
        execute "alter table users drop foreign key fk_user_type_id"

        #Drop the type_id column
        remove_column :users, :type_id
    end
end

ご覧のとおり、問題のある部分が 2 つあります。最初に、すべての移行を連続して実行する場合に必要な最初のモデルの行作成部分、次に「admin」列を「type_id」列にマップする 2 番目の移行の「更新」部分です。

何かアドバイス?

4

2 に答える 2

1

古い User.admin で UserType をロードするよりも、fk を使用する方が「型にはまらない」と思います。これはかなり頻繁に発生すると思います。

fk を使用すると、ユーザーを混乱させる醜い mysql エラーが発生します。それ以外の場合は、AR 検証とフックを使用して参照整合性を強制すると、アプリのユーザー エクスペリエンス フローを壊さない、きれいでよく統合されたエラー メッセージが表示されます。

一度実行される移行について心配する必要はありません。コードの外に置くビジネス ロジックについて考えてください。

これはすべて意見/慣習の問題ですが、私の洞察が何らかの形で役立つことを願っています.

于 2010-05-22T07:38:26.743 に答える
0

ファイル db/seeds.rb は、この目的で一般的に使用されます。そこに配置されたレコードは、 rake db:setup

ただし、レールがこの問題に陥ることは常にあります。db/seeds フォルダーを提供し、レコードを追加するための日付スタンプ付きシードファイル (おそらく .yml) を持ち、システム テーブル内のシード データを追跡して元に戻したり更新したりできるようにするプラグインを作成することを考えていました。

于 2010-05-23T23:41:50.013 に答える