3

スノーボードレンタル店にrailsアプリを実装しているとしましょう。

特定のスノーボードは、次の3つの状態のいずれかになります。

  1. メンテナンスのために離れて
  2. 店舗Xで入手可能
  3. 顧客Yに貸し出し中

会社は、のレンタル履歴を表示できる必要があります

  • 特定のスノーボード
  • 特定の顧客

レンタル履歴には、時間データを含める必要があります(たとえば、2009年12月1日から2009年12月3日までのSallyレンタルスノーボード0123)。

モデルをどのように設計しますか?4つの列(id、state、customer、store)を持つスノーボードテーブルがあり、状態が変化するたびに、このテーブルからタイムスタンプとともに行をsnowboard_historyテーブルにコピーしますか?

ありがとう!

(注:私は実際にレンタル店を実装しようとはしていません。これは私が考えることができる最も単純なアナログでした。)

4

2 に答える 2

10

仕事を成し遂げるために、プラグインのペアを使用します。これは 4 つのモデルを使用します。スノーボード、ストア、ユーザー、監査。

act_as_state_machineおよびact_as_audited

AASM は状態遷移を簡素化します。監査は必要な履歴を作成します。

Store と User のコードは簡単で、acts_as_audited が監査モデルを処理します。

class Snowboard < ActiveRecord::Base

  include AASM
  belongs_to :store
  

  aasm_initial_state :unread
  acts_as_audited :only => :state

  aasm_state :maintenance
  aasm_state :available
  aasm_state :rented

  aasm_event :send_for_repairs do
    transitions :to => :maintenance, :from => [:available]
  end

  aasm_event :return_from_repairs do
    transitions :to => :available, :from => [:maintenance]
  end

  aasm_event :rent_to_customer do
   transitions :to => :rented, :from => [:available]
  end

  aasm_event :returned_by_customer do
    transitions :to => :available, :from => [:rented]
  end
end

class User < ActiveRecord::Base
  has_many :full_history, :class_name => 'Audit', :as => :user,
   :conditions => {:auditable_type => "Snowboard"}
end    

状態が変化したときのコントローラーアクション中に顧客が current_user であると仮定すると、それで十分です。

スノーボードの履歴を取得するには:

@snowboard.audits

顧客のレンタル履歴を取得するには:

@customer.full_history

ヘルパー メソッドを作成して、顧客の履歴をより便利なものにすることができます。たぶん彼のようなもの:

 def rental_history
    history = []
    outstanding_rentals = {}
    full_history.each do |item|
      id = item.auditable_id
      if rented_at = outstanding_rentals.keys.delete(id)
        history << { 
          :snowboard_id => id, 
          :rental_start => rented_at,
          :rental_end => item.created_at
        }   
      else
        outstanding_rentals[:id] = item.created_at
      end
    end
    history << oustanding_rentals.collect{|key, value| {:snowboard_id => key,  
      :rental_start => value}
  end
end
于 2009-11-16T16:02:51.370 に答える
2

まず、Snowboard、Customer、Store用に別々のモデルを生成します。

script/generate model Snowboard name:string price:integer ...
script/generate model Customer name:string ...
script/generate model Store name:string ...

(レールは自動的に生成idcreated_atmodified_at日付を生成します)

履歴を保持するために、必要な場合を除いて(たとえば、顧客がレンタルした価格を追跡したい場合)、これらのテーブルから行/値をコピーしません。

代わりに、あなたが説明したのと同様のプロパティを使用して、SnowboardEventモデルを作成します(必要に応じて呼び出すことSnowboardHistoryもできますが、個人的には新しい履歴を作成するのは奇妙に感じます)。

  • ev_type(つまり、0は返品、1は保守、2は賃貸...)
  • snowboard_id(nullではない)
  • customer_id
  • store_id

例えば、

script/generate model SnowboardEvent ev_type:integer snowboard_id:integer \
    customer_id:integer store_id:integer

次に、、、、のすべての関係を設定SnowboardEventSnowboardます。Snowboardは、次のような機能を持つことができます。CustomerStorecurrent_statecurrent_store

class Snowboard < ActiveRecord::Base
  has_many :snowboard_events
  validates_presence_of :name

  def initialize(store)
    ev = SnowboardEvent.new(
         {:ev_type => RETURN,
          :store_id => store.id,
          :snowboard_id = id,
          :customer_id => nil})
    ev.save
  end

  def current_state
    ev = snowboard_events.last
    ev.ev_type          
  end

  def current_store
    ev = snowboard_events.last
    if ev.ev_type == RETURN
      return ev.store_id
    end
    nil
  end

  def rent(customer)
    last = snowboard_events.last
    if last.ev_type == RETURN
      ev = SnowboardEvent.new(
           {:ev_type => RENT,
            :snowboard_id => id,
            :customer_id => customer.id
            :store_id => nil })
      ev.save
    end
  end

  def return_to(store)
    last = snowboard_events.last
    if last.ev_type != RETURN
      # Force customer to be same as last one
      ev = SnowboardEvent.new(
           {:ev_type => RETURN,
            :snowboard_id => id,
            :customer_id => last.customer.id
            :store_id => store.id})
      ev.save
    end
  end
end

そして、顧客も同じhas_many :snowboard_eventsです。

Snowboard.snowboard_eventsスノーボードや顧客の履歴を確認するには、またはを使用してレコードをループするだけCustomer.snowboard_eventsです。「時間データ」はcreated_at、これらのイベントのプロパティになります。オブザーバーの使用は必要ではないと思います。

注:上記のコードはテストされておらず、決して完璧ではありませんが、アイデアを得るためだけです:)

于 2009-11-16T14:33:58.040 に答える