2017-02-05 4 views
1

私はユーザーが放送番組やエピソードを追跡できるRailsアプリを持っています。多態性は動的クラスと関連しています(他の関係から取られました)

(まだ)視聴していない番組を追跡するプロセスを簡素化するために、ユーザーは自分のアカウントを他のサービスと同期させることができます。ユーザー設定ページで、同期するサービスを選択できます。

同期するために、私は自分のプロファイルを他のサービスからロードし、最後の同期からの変化を検出し、それに応じてDBを更新するアルゴリズムを実行します。最後の同期ステータスを保存するために、Show IDごとに、ショーIDと、そのショーの現在のステータスを同期サービスに保存する "UsersSyncIdStatus"オブジェクトを作成します。

サービスでは自分のウェブサイトと同じショーIDを使用しないので、ショーIDからショーIDに「変換」するために使用できるテーブルがあることに注意してください。各サービスが提供する情報は異なるため、異なる表に格納する必要があります。

今、これはDBスキーマが設定されている方法(の簡易版)である:特に

create_table "service1_ids", force: :cascade do |t| 
    t.integer "service_id", null: false 
    t.integer "show_id", null: false 
    [...] 
end 

create_table "service2_ids", force: :cascade do |t| 
    t.integer "service_id", null: false 
    t.integer "show_id", null: false 
    [...] 
end 

create_table "users_sync_id_statuses", force: :cascade do |t| 
    t.integer "user_id" 
    t.integer "service_id",     null: false 
    t.integer "sync_status", default: 0, null: false 
    t.datetime "sync_date",    null: false 
    [...] 
end 

create_table "users", force: :cascade do |t| 
    [...] 
    t.datetime "synced_at" 
    t.boolean "sync_enabled",    default: false, null: false 
    t.integer "sync_method",    default: 0,  null: false 
    [...] 
end 

users.sync_methodは、ユーザが同期のために選択されたサービスを記憶する列挙である:

SYNC_METHODS = { 
    0 => { 
     symbol: :service1, 
     name: 'Service1', 
     model_name: 'Service1Id', 
     show_scope: :service1_ids 
    } 
    1 => { 
     symbol: :service2, 
     name: 'Service2', 
     model_name: 'Service2Id', 
     show_scope: :service2_ids 
    } 
} 

これは、SyncHelper::SYNC_METHODS[current_user.sync_method][:model_name]を実行するだけで、特定のユーザーのIDのモデル名を簡単に知ることができることを意味します。

ここで、「users_sync_id_statuses」と「serviceN_ids」の関係をどのようにすることができますか? 「service_id」列がどのクラスに対応しているかを知るためには、ユーザーモデルを「尋ねる」必要があります。

私は現在、それはメソッドとして実装されています:

class User 
    def sync_method_hash 
     SyncHelper::SYNC_METHODS[self.sync_method] 
    end 

    def sync_method_model 
     self.sync_method_hash[:model_name].constantize 
    end 
end 

class UsersSyncIdStatus 
    def service_id_obj 
     self.user.sync_method_model.where(service_id: self.service_id).first 
    end 
end 

をしかし、UsersSyncIdStatus.service_id_objは方法ではなく、私は関係ができますすべてのファンシーなものを行うことができないことを意味関係、です。例えば、私は簡単に特定のユーザーのUsersSyncIdStatusをつかむとIDを表示することはできません。

current_user.sync_id_statuses.where(service_id_obj: {show_id: 123}).first 

Iが多型の関係にそれを回すことができますが、私は本当に含まれているために、テキスト列を追加する必要がありますする必要はありません(ユーザーが同期サービスを切り替えるために、そのユーザーのすべてのUsersSyncIdStatusesが破棄されるため、ユーザーはUsersSyncIdStatusesに2つ以上のサービスタイプを持つことはありません)。

アイデア?前もって感謝します!

+0

多態性の関係を試していないというあなたの推論や、「has_many:through」さえ理解できません。 'sync_method'は、あなたが典型的にモデルで見つけたものの型です。 'has_many'のような関連はRuby文であり、条件付きで制御することができます。あなたはデータベースにそれをコーディングするのが難しいようですが、なぜですか? –

+0

多相関連では、関係のモデル名を含むテキスト列を 'users_sync_id_statuses'テーブルに追加する必要があります。 1人のユーザーが何千もの 'users_sync_id_statuses'行を持ち、それらのすべてが同じモデルクラスとの関係を持つため、それらのすべての1つに列を追加することはデータベーススペースの膨大な浪費です...問題は各ユーザーはその関係の異なるモデルを持つ可能性があり、関係モデルのユーザーオブジェクトを自動的に照会する関係を、すべての行に格納するのではなく、必要としました。 – rpinheiro

+0

私は、正直言って、私はそれらを使用して終了しませんでした。しかし、私の推薦は、関係宣言をデータベースから取り除こうとすることに至りました。外部キーを保持し、ActiveRecordアソシエーションを使用してクエリを構築します。このアプローチについてのご予約はありますか? –

答えて

1

私はバニラのレール5が私がしたいことをサポートしているとは思わない、誰かが間違っていれば私を修正してください。

config/initializers/belongs_to_polymorphic_type_send.rb

# Modified from: rails/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb 
module ActiveRecord 
    # = Active Record Belongs To Polymorphic Association 
    module Associations 
     class BelongsToPolymorphicAssociation < BelongsToAssociation #:nodoc: 
      def klass 
       type = owner.send(reflection.foreign_type) 
       type.presence && (type.respond_to?(:constantize) ? type.constantize : type) 
      end 
     end 
    end 
end 

app/models/users_sync_id_status.rb

方法をレールにいくつかの研究が多型の関係を実装した後

それでも、私は比較的容易に猿パッチレール5は、この機能を追加することができました

class UsersSyncIdStatus 
    belongs_to :service_id_obj, polymorphic: true, foreign_key: :service_id, primary_key: :service_id 
    def service_id_obj_type 
     self.user.sync_method_model 
    end 
end 

このモンキーパッチでは、belongs_to多相関連は、型フィールドがvarであるとはみなしませんcharカラムを呼び出す代わりに、オブジェクトのメソッドとして呼び出します。これは、古い振る舞いを破ることなく、あなた自身の動的な振る舞いを非常に簡単に追加できることを意味します(AFAIKはそれについて集中的なテストをしませんでした)。

私の具体的な使用例として、sync_id_obj_typeメソッドは多態性関連で使用するクラスのユーザーオブジェクトをクエリします。

関連する問題