首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >制作一个比萨饼并选择你的配料

制作一个比萨饼并选择你的配料
EN

Code Review用户
提问于 2016-12-01 16:15:22
回答 2查看 289关注 0票数 3

我在下面创建了一个场景,在这个场景中,用户可以构建一个比萨饼并选择他们的配料,然后订购他们的比萨:

代码语言:javascript
运行
复制
require 'active_record'
require 'logger'

ActiveRecord::Base.establish_connection adapter: 'sqlite3', database: ':memory:'
ActiveRecord::Base.logger = Logger.new $stdout
ActiveSupport::LogSubscriber.colorize_logging = false

ActiveRecord::Schema.define do
  self.verbose = false

  create_table :pizzas do |t|
    t.string :name
  end

  create_table :pizzas_toppings_groups do |t|
    t.integer :pizza_id
    t.integer :toppings_group_id
  end

  create_table :toppings_groups do |t|
    t.string :name
    t.integer :user_id
  end

  create_table :toppings do |t|
    t.integer :toppings_group_id
    t.string :name
  end

  create_table :orders do |t|
    t.integer :user_id
  end

  create_table :ordered_pizzas do |t|
    t.integer :order_id
    t.string :name
  end

  create_table :ordered_pizza_toppings do |t|
    t.integer :ordered_pizza_id
    t.integer :topping_id
  end
end

class Pizza < ActiveRecord::Base
  has_many :pizzas_toppings_groups
  has_many :toppings_groups, through: :pizzas_toppings_groups
  has_many :toppings, through: :toppings_groups
end

class PizzasToppingsGroup < ActiveRecord::Base
  belongs_to :pizza
  belongs_to :toppings_group
end

class ToppingsGroup < ActiveRecord::Base
  belongs_to :user
  has_many :pizzas_toppings_groups
  has_many :pizzas, through: :pizzas_toppings_groups
  has_many :toppings

  validates :name, presence: true
end

class Topping < ActiveRecord::Base
  belongs_to :toppings_group

  validates :name, presence: true
end

class Order < ActiveRecord::Base
  belongs_to :user
  has_many :ordered_pizzas
end

class OrderedPizza < ActiveRecord::Base
  belongs_to :order

  has_many :ordered_pizza_toppings
  has_many :toppings, through: :ordered_pizza_toppings
end

class OrderedPizzaTopping < ActiveRecord::Base
  belongs_to :ordered_pizza
  belongs_to :topping
end

# admin defines pizzas and available toppings groups and related toppings

cheesy_pizza = Pizza.create(name: "cheeeeeeeese")

cheap_cheesy_group = cheesy_pizza.toppings_groups.create!(name: 'basic cheeses')
mozza = cheap_cheesy_group.toppings.create!(name: 'mozzarella')

fancy_cheesy_group = cheesy_pizza.toppings_groups.create(name: 'fancy cheeses')
goat = fancy_cheesy_group.toppings.create!(name: 'goat')
cheddar = fancy_cheesy_group.toppings.create!(name: 'cheddar')

# imagine there is a fancy user interface where the user can choose 
# toppings from topping groups, but certain groups
# have min/max limits on the toppings you can choose, etc etc
# for now here's a method that
# just takes in chosen toppings, and ties it to the ordered_pizza:
def create_order(pizza:, chosen_toppings:)
  Order.transaction do
    order = Order.create
    ordered_pizza = order.ordered_pizzas.create(name: pizza.name)
    ordered_pizza.toppings << chosen_toppings # imagine this line is lots of complicated validations
    order
  end
end

# user orders a pizza

jims_order = create_order(pizza: cheesy_pizza, chosen_toppings: [mozza, goat])

jims_order.reload

jims_order.ordered_pizzas

# for business reasons, some toppings are no longer available, and are removed.

mozza.destroy
goat.destroy

jims_order.reload
jims_order.ordered_pizzas.first.toppings

历史的完整性现在被破坏了!吉姆订好的比萨饼和所有其他点菜的比萨饼上都缺少这些配料。

几个问题:

  • 这是一个理想的方式,以节省订单与他们的定制比萨饼?
  • 避免历史诚信问题的最佳方法是什么?
EN

回答 2

Code Review用户

回答已采纳

发布于 2016-12-03 15:28:01

以这种方式保存定制的比萨,看起来还可以,但也取决于应用程序的其余部分是如何构造的。我认为你在这里最关心的应该是你在第二个问题中提到的历史数据的完整性。

当涉及到数据时,它们所处的环境帮助您了解应该如何对待它们。例如,在经营一家在线订购比萨饼店的企业时,一旦顾客可以买到的配料就不能被“删除”。在这些术语中,它们可能变得不可用、中断或其他什么,但不能删除。如果顾客要求你在他们的比萨饼中添加意大利辣香肠,你就不能回复:“哦,我们删除了辣香肠!”

一旦数据命中生产,它们将始终是您应用程序的一部分,尽管它们的状态如何变化,所以您必须把它们当作总是存在的。

这在某种程度上是一个常见的问题,有几种解决办法。我可以提到我过去用过的两种。

第一种方法:软数据删除

第一种方法是对您的数据使用某种软删除策略。你可以在互联网上找到很多关于这一技术的帖子,你也可以找到很多宝石 for ActiveRecord,这些都可以直接用在盒子里。实际上,您使用软删除实现的是,当您删除数据时,并不是真正地删除它们,而是将它们标记为已删除,以便可以将它们排除在查询之外。

最常见的方法是向表中添加一个新列,该列表示记录已被删除(例如,deleted_at:datetimedeleted:boolean),或者添加一个单独的镜像表,其中将“删除”数据(例如deleted_toppings)。这两种选择各有优缺点,因此这取决于应用程序是如何设计的。

记住,软删除可能会增加应用程序的复杂性。例如,当您要求Topping#name成为unique并且尝试添加一个新的名称相同的名字,并且已经属于一个软删除的顶部时,会发生什么呢?

第二种方法:定制比萨饼

的单独模型

第二种方法是以完全不同的方式对待OrderedPizzaToppings。这里的想法是将OrderedPizzaToppingPizzaTopping分离开来。

看起来可能是这样的:

代码语言:javascript
运行
复制
class OrderedPizza < ActiveRecord::Base
  belongs_to :order

  has_many :ordered_pizza_toppings
end

class OrderedPizzaTopping < ActiveRecord::Base
  belongs_to :ordered_pizza
end

每次创建一个订购的披萨时,您都会将每个Topping的S数据转储到一个OrderedPizzaTopping实例中,然后保存它。

代码语言:javascript
运行
复制
class OrderedPizzaTopping < ActiveRecord::Base
  belongs_to :ordered_pizza

  def self.from(topping = Topping.new)
    create!(data: topping.to_h)
  end
end

# ....

def create_order(pizza:, chosen_toppings:)
  Order.transaction do
    order = Order.create
    ordered_pizza = order.ordered_pizzas.create(name: pizza.name)
    ordered_pizza.toppings << chosen_toppings.map { |t| OrderPizzaTopping.from(t) }
    order
  end
end

如果您注意到OrderedPizzaTopping所做的唯一事情就是存储PizzaTopping的散列版本。只是一个简单的数据结构,包含名称、描述、价格、图像url等。现在,即使PizzaTopping在某个时候被硬删除,您也将始终拥有原始数据,这将允许您以任何想要的方式表示Order。可以选择地存储对原始PizzaTopping的引用,以防它存在于数据库中。

历史数据完整性不仅仅是关于已删除的数据。如果有人改变了已经存在一年的Topping的价格,会发生什么呢?所有的订单,包括比萨饼包含这一顶部将受到影响。我认为这里的关键字是审计。审核一个模型,意味着记录整个时间内的数据更改。

票数 2
EN

Code Review用户

发布于 2016-12-03 00:29:29

我要说的是,最好的表达方式是向toppings中添加一个布尔标志列,该列指示当前是否可以订购顶部。

从SQL数据库中删除一行的“语义”含义是它包含的数据不再存在,并且/或再也不会被应用程序访问。

向面向客户端隐藏某些数据,同时在面向业务端保存这些数据的语义方法是创建一个可以对查询进行作用域的标志列。

请注意,您可以使用域/查找表/enum/多个布尔值来表达更复杂的想法。

可用=> 凤尾鱼,意大利香肠

季节性=> 龙虾

停产=> Soylent酒吧

被禁的=> 鹅肝、大麻油

票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/148664

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档