1

私は Ruby の初心者であり、DataMapper やその他の ORM の初心者です。私は Perl のバックグラウンドを持っており、実際には OOP タイプの開発者ではありません。だから私はここで未知の領域をさまよっています。長文の質問で申し訳ありません...

このプロジェクトでは、deviceclasses と deviceclasses の下にマップされるデバイスの概念があります。Deviceclasses は、子 deviceclasses を持つことができる必要があります。共通のルート deviceclass 名 (つまり、すべての deviceclass が由来するルート) は "FOO" または "BAR" (このサンプル コードでは) と呼ばれ、それぞれに任意の子 devicesclasses のセットを含めることができます。最後に、deviceclass には最終的にデバイスが含まれます。

Deviceclasses には多くの deviceclass があります Deviceclasses には多くのデバイスがあります deviceclass には 1 つの deviceclass_name があります 多くのデバイスは deviceclass に属します

だから、IE:

FOO
    JOHNSHOUSE
         UPSTAIRS
             device1
             device2
         DOWNSTAIRS
             device1
             device2
    MANYHOUSES
        JOE
            GARAGE
                device1
                device2
        SUZY
            BEDROOM
                device1
                device2
                device3
        TIM
            LIVINGROOM
                device1
    ARBITRARY
        device1
        SOMEPLACE
            device1
            device2
BAR
    ENGLAND
        LONDON
            MYHOUSE
                BEDROOM
                    device1
                    device2
                    device3

そして、ここで私は立ち往生しています...デバイスとデバイスクラスはDBに自律的に追加できる必要があり、それらの関連付けは後で実行されます。だから、私はできません

deviceclass = MyDB::Deviceclass.new
device      = MyDB::Device
deviceclass.device.new(blah)

この一連の質問の基礎となる関連モデルを含む私のモジュール...

質問 1 - 私はこれを正しく行っていますか? Deviceclass の下の self.validate_root_deviceclasses メソッドに注意してください。n何よりも先に DB にルート デバイスクラスを用意する必要があるため、このメソッドでそれらを作成します。残念ながら、プロパティの更新は機能しません。私はそれについて何らかの方向性が欲しいです。

module DeviceDB
    ROOT_DEVICECLASSES %w{FOO BAR}

    class Deviceclass
        include DataMapper::Resource
        property :id, Serial
        property :hw_id, String,                :unique  => true
        property :root_deviceclass, Boolean,    :default => false
        property :parent_deviceclass_id, Integer
        property :deviceclass_name, String
        property :updated_at, DateTime
        property :created_at, DateTime

        has n, :devices,       :through => Resource
        has n, :deviceclasses, :through => Resource
        has 1, :deviceclass, self, {:through=>:deviceclasses, :via=>:parent_deviceclass_id}

        def self.validate_root_deviceclasses
            root_deviceclasses = all(:root_deviceclass => true)

            if root_deviceclasses.count > 0 
# get whats in the db now
                db      = Array.new(root_deviceclasses.map(&:deviceclass_name))
# match it against the global list (top of this file)
                missing = ROOT_DEVICECLASSES.map{|root| root unless db.grep(/#{root}/i)[0]}.compact

# if something's missing, add it.
                missing.each do |missing|
                    begin
                        create(:deviceclass_name => missing, :root_deviceclass => true).save
                    rescue DataMapper::SaveFailureError => e
                        @error = [e.resource.errors.map{|err| err}].join(', ')
                        return(false)
                    end 
                end 
            else
                begin
                    ROOT_DEVICECLASSES.each do |root|
                        create(:deviceclass_name => root, :root_deviceclass => true).save
                    end 
                rescue DataMapper::SaveFailureError => e
                    @error = [e.resource.errors.map{|err| err}].join(', ')
                    return(false)
                end 
            end 

            begin
                default = first(:deviceclass_name => 'PTS').id

                property :parent_deviceclass_id, Integer, :default => default # fail
                DataMapper.finalize                                           # fail
                return(self)
            rescue DataMapper::SaveFailureError => e
                @error = [e.resource.errors.map{|err| err}].join(', ')
            end

            return(true)
        end
    end

    class Device
        include DataMapper::Resource
        property :id, Serial
        property :deviceclass_id, Integer
        property :device_id, String, :unique => true
        property :devicename, String
        ... more properties...
        property :updated_at, DateTime
        property :created_at, DateTime

        belongs_to :deviceclass, :required => false
    end

    DataMapper.finalize
    DataMapper.auto_upgrade!

    Deviceclass.validate_root_deviceclasses
end

質問 2: deviceclasses とデバイスを関連付ける魔法のような方法はありますか? それとも、デバイスの ID を取得し、更新を介して関連付けられた deviceclass に関連付けるという難しい方法で行う必要がありますか?

質問 3: :default を追加することでテーブルを効果的に変更する、テーブルが既に移行された後にモデルにプロパティを追加する方法はありますか (上記の失敗例を参照)。そうでない場合、モデルの作成中にデフォルト値を取得する方法はありますか? ラムダが思い浮かびますが、それはテーブルが既に存在し、ROOT_DEVICENAMES が既に追加されている場合にのみ機能します。

4

1 に答える 1

1

スキーマと自律的に項目を追加することに関する最初の質問については、dm-is-treefor yourを使用することを検討してくださいDeviceclass。多くの作業が行われます。以下は、アイテムを作成し、「後で」関連アイテムを追加する例です。

require 'rubygems'
require 'data_mapper'
require 'dm-is-tree'

# setup
DataMapper::Logger.new($stdout, :debug)
DataMapper.setup(:default, 'sqlite::memory:')

# models
class Deviceclass
  include DataMapper::Resource

  property :id,          Serial
  property :hw_id,       String,   :unique  => true
  property :name,        String
  property :updated_at,  DateTime
  property :created_at,  DateTime

  is :tree, :order => :name
  has n, :devices
end

class Device
  include DataMapper::Resource

  property :id,               Serial
  property :device_class_id,  Integer
  property :name,             String
  property :updated_at,       DateTime
  property :created_at,       DateTime

  belongs_to :deviceclass, :required => false
end

# go!
DataMapper.finalize
DataMapper.auto_upgrade!

# make the root deviceclass
parent = Deviceclass.create(:name => "Root")

# later on make a child
child = Deviceclass.create(:name => "Child")
# and add it to the parent
parent.children << child

# again later, create some devices
d1 = Device.create(:name => "D1")
d2 = Device.create(:name => "D2")

# add them
parent.devices << d1
child.devices << d2

# get stuffs
puts parent.children
puts child.root
puts parent.devices
puts child.devices

検証を使用して欠落している Deviceclasses を生成するのが良い考えかどうかはわかりません。初期データが常に変化していない場合は、起動時にシード スクリプトを実行します。dm-sweatshopなどを使用してデータベースをシードできます。

#3についてもう少し詳しく説明する必要があると思いますが、すでに:default => 'foo'使用しているので知っているかもしれないDeviceclassのデフォルト名(追加できます)が必要ですか?:default:)

于 2013-03-21T09:19:50.240 に答える