mač*_*ček 9 schema activerecord ruby-on-rails
我想记录用户何时更改其地址.
这样,当下订单时,它将始终能够引用订单放置时使用的用户地址.
users (
id
username
email
...
)
user_addresses (
id
label
line_1
line_2
city
state
zip
...
)
user_addresses_map (
user_id
user_address_id
start_time
end_time
)
orders (
id
user_id
user_address_id
order_status_id
...
created_at
updated_at
)
Run Code Online (Sandbox Code Playgroud)
select ua.*
from orders o
join users u
on u.id = o.user_id
join user_addressses_map uam
on uam.user_id = u.id
and uam.user_address_id = o.user_address_id
join user_addresses ua
on ua.id = uam.user_address_id
and uam.start_time < o.created_at
and (uam.end_time >= o.created_at or uam.end_time is null)
;
Run Code Online (Sandbox Code Playgroud)
@KandadaBoggu发布了一个很好的解决方案.在维斯塔版本的插件是一个很好的解决方案.
下面的代码段取自http://github.com/laserlemon/vestal_versions
technoweenie的acts_as_versioned是一个很好的开始,但它无法跟上ActiveRecord在2.1版本中引入脏对象的步伐.此外,每个版本化的模型都需要自己的版本表,该表复制了大多数原始表的列.然后在版本表中填充通常复制大多数原始记录属性的记录.总而言之,不是很干.
vestal_versions只需要一个版本表(与其父模型多态关联),并且不需要对现有表进行任何更改.但它通过存储仅模型变化的序列化哈希来实现DRYer的一步.想想现代版控制系统.通过遍历变更记录,模型可以恢复到任何时间点.
而这正是vestal_versions所做的.模型不仅可以恢复到以前的版本号,还可以恢复到日期或时间!
Har*_*tty 13
使用Vestal版本插件:
有关更多详细信息,请参阅此屏幕演示.
class Address < ActiveRecord::Base
belongs_to :user
versioned
end
class Order < ActiveRecord::Base
belongs_to :user
def address
@address ||= (user.address.revert_to(updated_at) and user.address)
end
end
Run Code Online (Sandbox Code Playgroud)
以为我会添加一个更新的答案.似乎paper_trailgem已成为Rails中最受欢迎的版本.它也支持Rails 4.
https://github.com/airblade/paper_trail
从他们的自述文件:
要设置和安装:
gem 'paper_trail', '~> 3.0.6'
bundle exec rails generate paper_trail:install
bundle exec rake db:migrate
Run Code Online (Sandbox Code Playgroud)
基本用法:
class Widget < ActiveRecord::Base
has_paper_trail
end
Run Code Online (Sandbox Code Playgroud)
对于类的特定实例Widget:
v = widget.versions.last
v.event # 'update' (or 'create' or 'destroy')
v.whodunnit # '153' (if the update was via a controller and
# the controller has a current_user method,
# here returning the id of the current user)
v.created_at # when the update occurred
widget = v.reify # the widget as it was before the update;
# would be nil for a create event
Run Code Online (Sandbox Code Playgroud)
我只玩过它,但我即将开始一个非常雄心勃勃的网站,需要对某些类进行良好的版本化,我决定使用它paper_trail.
===编辑====
我已经paper_trail在www.muusical.com上实现了生产中的宝石,并且使用上述方法效果很好.唯一的变化是我在使用gem 'paper_trail', '~> 4.0.0.rc'我的Gemfile.
从数据架构的角度来看,我建议解决您提出的问题
...下订单时,它将始终能够引用下订单时使用的用户地址。
...您只需将该人的地址复制到 Order 模型中即可。这些项目将在 OrderItem 模型中。我会将该问题重新表述为“订单发生在某个时间点。OrderHeader 包括该时间点的所有相关数据。”
是不正常的吗?
不,因为 OrderHeader 代表一个时间点,而不是正在进行的“真相”。
以上是处理订单标题数据的标准方法,与跟踪模型中的所有更改相比,它从您的架构中消除了很多复杂性。
--坚持解决真正问题的解决方案,而不是可能的问题--是否有人需要用户更改的历史记录?或者您是否只需要订单标题来反映订单本身的实际情况?
补充:请注意,您需要知道最终使用哪个地址将订单/发票运送到。您不想查看旧订单并查看用户的当前地址,而是希望查看订单发货时订单使用的地址。有关更多信息,请参阅下面的评论。
请记住,系统的最终目的是模拟现实世界。在现实世界中,一旦订单打印出来并与订购的商品一起发送,订单的收货方就不会再发生任何变化。如果您要发送软商品或服务,则需要从更简单的示例中进行推断。
订单系统是一个很好的案例,了解业务需求和现实非常重要——不要只与业务经理交谈,还要与一线销售人员、订单文员、应收账款文员、运输部人员交谈, 等等。
| 归档时间: |
|
| 查看次数: |
11333 次 |
| 最近记录: |