在 Rails 中实现租赁商店:如何跟踪一段时间内的库存状态?
-
20-09-2019 - |
题
假设您正在为一家滑雪板租赁商店实施 Rails 应用程序。
给定的滑雪板可以处于以下 3 种状态之一:
- 外出维护
- 可在 X 商店购买
- 贷款给客户 Y
公司需要能够查看租赁历史记录
- 特定的滑雪板
- 特定客户
租赁历史需要包括时间数据(例如Sally 从 12 月起租用了滑雪板 0123。2009 年 1 月 至 12 月3 2009)。
你会如何设计你的模型?您是否有一个包含 4 列(id、state、customer、store)的滑雪板表,并在每次状态更改时将此表中的行以及时间戳复制到 Snowboard_history 表中?
谢谢!
(笔记:我实际上并不是想开一家租赁店;我只是想开一家租赁店。这只是我能想到的最简单的类比。)
解决方案
我会使用一对插件来完成工作。这将使用四个模型。滑雪板、商店、用户和审计。
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
其他提示
首先,我将为滑雪板、客户和商店生成单独的模型。
script/generate model Snowboard name:string price:integer ...
script/generate model Customer name:string ...
script/generate model Store name:string ...
(rails自动生成 id
和 created_at
, modified_at
日期)
为了保留历史记录,我不会从这些表中复制行/值,除非有必要(例如,如果您想跟踪客户租用它的价格)。
相反,我会创建 SnowboardEvent 模型(您可以将其称为 SnowboardHistory
如果您愿意,但就我个人而言,用您描述的类似属性创造新的历史感觉很奇怪:
ev_type
(IE。0 表示退货,1 表示维护,2 表示租赁...)snowboard_id
(不为空)customer_id
store_id
例如,
script/generate model SnowboardEvent ev_type:integer snowboard_id:integer \
customer_id:integer store_id:integer
然后我会设置之间的所有关系 SnowboardEvent
, Snowboard
, Customer
和 Store
. 。滑雪板可以具有以下功能 current_state
, current_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
这些事件的财产。我不认为使用观察者是必要的或相关的。
笔记:上面的代码没有经过测试,也绝不是完美的,只是为了得到这个想法:)