Ruby on rails RubyonRails:检查商店拥有的产品数量
为了更好地理解Rails,我正在忙于一个测试/练习项目 在我的例子中,我有三个模型:商店、用户和产品 商店可以有三种类型:基本型、中型、大型。基本型最多可以有10个产品,中型50个,大型100个 我试图验证这类数据、商店类型,并在创建新产品时检查它拥有多少产品 到目前为止,我在shop.rb中提出了这段代码,但它不起作用:Ruby on rails RubyonRails:检查商店拥有的产品数量,ruby-on-rails,ruby,Ruby On Rails,Ruby,为了更好地理解Rails,我正在忙于一个测试/练习项目 在我的例子中,我有三个模型:商店、用户和产品 商店可以有三种类型:基本型、中型、大型。基本型最多可以有10个产品,中型50个,大型100个 我试图验证这类数据、商店类型,并在创建新产品时检查它拥有多少产品 到目前为止,我在shop.rb中提出了这段代码,但它不起作用: def lol account = Shop.find_by_sql "SELECT account FROM shops WHERE user_id = 4
def lol
account = Shop.find_by_sql "SELECT account FROM shops WHERE user_id = 4 LIMIT 1"
products = Product.count_by_sql "SELECT COUNT(*) FROM products WHERE shop_id = 13"
if account = 1 && products >= 10
raise "message"
elsif account = 2 && products >= 50
raise "message"
else account = 3 && products >= 100
raise "message"
end
end
我甚至不知道我的解决方案背后的逻辑是否正确。也许我应该使用
has_many
它的“大小”方法是什么?我不知道。:) 应该对你有所帮助。至少将
account=1
更改为account==1
。account=2
和account=3
也是如此
除此之外,我建议您查看以了解Rails的使用
话虽如此,我建议如下:
class Shop < ActiveRecord::Base
has_many :products
validates :products_within_limit
# Instead of the 'account' column, you could make a 'max_size' column.
# Then you can simply do:
def products_within_limit
if products.size > max_size
errors.add_to_base("Shop cannot own more products than its limit")
end
end
def is_basic?
products.size >= 10 && products.size < 50
end
def is_medium?
products.size >= 50 && products.size < 100
end
def is_big?
products.size >= 100
end
def shop_size
if self.is_basic?
'basic'
elsif self.is_medium?
'medium'
elsif self.is_big?
'big'
end
end
end
这里有一种可能的实现方法。这是我自己的风格,让Ruby模仿抽象类(Shop)的行为。YMMV 编辑:注意,我将OP示例中的“account”变量替换为使用ActiveRecord的继承,后者使用“type”列来执行基本相同的功能,但使用继承来表示不同类型的商店及其各自的产品限制。OP的原始示例可能违反了标准,而STI是解决这一问题的一种方法 编辑:就好像我不够学究,从技术上讲,这并不是一个真正的利斯科夫违规行为,更像是一个错误。它们都是同一主题的变体。你明白了
class Product < ActiveRecord::Base
belongs_to :shop
end
class Shop < ActiveRecord::Base
has_many :products
belongs_to :user
validates :products_within_limit
def products_within_limit
if products.count > limit
errors.add_to_base("Shop cannot own more products than its limit")
end
end
def limit
raise "limit must be overridden by a subclass of Shop."
end
end
class BasicShop < Shop
def limit
10
end
end
class MediumShop < Shop
def limit
50
end
end
class LargeShop < Shop
def limit
100
end
end
shop = BasicShop.create
10.times {Product.create(:shop => shop)}
shop.reload
shop.valid? # is true
shop.products << Product.new
shop.valid? # is false
类产品限制
错误。将\添加到\基础(“商店不能拥有超过其限制的产品”)
结束
结束
def限制
raise“限制必须被Shop的子类覆盖。”
结束
结束
class BasicShopshop)}
重新装填
商店,有效吗是真的
shop.products不需要这么难:
class Shop < ActiveRecord::Base
has_many :products
validate :check_nr_of_products
def check_nr_of_products
nr_of_products = products.size
errors[:base] << "Basic shops can have max 10 products" if account == 1 && nr_of_products > 10
errors[:base] << "Medium shops can have max 50 products" if account == 2 && nr_of_products > 50
errors[:base] << "Big shops can have max 100 products" if account == 3 && nr_of_products > 100
end
class-Shop
每次保存时都会检查此验证。您不需要检索“帐户类型”,假设它是商店的一个字段。同样,不要编写查询来计算产品的nr,而是使用执行此操作的size
函数
这是一个简单的解决方案。@Dave_Sims建议的STI解决方案有效且更面向对象。首先,感谢大家的大力帮助和深入讨论。:)
我从你的答案中提取了一些信息,以便组合出一个我能理解自己的解决方案。似乎在编程方面,我只能理解if-else语句,没有比这更复杂的了(
我所做的是:
class Shop < ActiveRecord::Base
belongs_to :user
has_many :products, :dependent => :destroy
validate :is_account
def is_account
if account == 1 && products.size < 11
elsif account == 2 && products.size < 51
else account == 3 && products.size < 101
end
end
商店现在是类型1,只有9种产品,但每当我单击“新产品”链接时,我就会被重定向到/products,并显示shops.upgrade.must消息
我不知道,似乎
account
in shop.rb没有返回正确的值。该列是int(11)类型,因此我猜它只能返回一个数字,但仍然…再次感谢您的大力支持。我最终从您的解决方案中窃取了一些内容并实现了以下代码:
#in shop.rb
validate :is_account
def is_account
if account == 1
limit = 10
elsif account == 2
limit = 50
else account == 3
limit = 100
end
errors.add(:base, "Reached maximum number of items for shop") if account == account && products.size >= limit
end
#in products_controller.rb
def new
if current_user.shop.nil?
flash[:alert] = I18n.t 'shops.create.must'
redirect_to :action => :index
elsif current_user.shop.invalid?
flash[:alert] = I18n.t 'shops.upgrade.must'
redirect_to :action => :index
else
@product = Product.new
end
end
到目前为止似乎还有效。希望我没有犯任何明显的错误
再次感谢!:)请随意添加带有否决票的评论。你到底不喜欢这里什么?请解释一下反对票。这里的设计基本上是坚固的。OP正在试验rails,这是一个很好的OOP解决方案,引入了STI和自定义验证。我可以在这里看到变化——使用类变量而不是“limit”方法或其他可能性。但是,这个解决方案是完全有效的。总之,没有解释,这些下注是无稽之谈,OP应该考虑我的解决方案或一些变体作为STI+自定义验证的一个很好的例子。p用“type”变量将模型弄乱会引起Liskov的愤怒。无论你想使用“类型”(或在这种情况下,“帐户”)在业务规则上旋转,你都应该考虑多态性(经典意义上的)解决方案。我投了赞成票。对不起,还是-1;-)谢谢船长!有时投票习惯可能会让人困惑。OP给出了一个“账户”变量,以根据所含产品的数量确定特定商店类型的有效性。您给出的不是验证,而是动态确定类型的方法。添加了验证建议,但我个人支持Dave的解决方案。您的验证测试是错误的。我不明白您想做什么,因为您的if块中没有代码。您应该通过执行错误来添加到错误中。将\u添加到\u base
或错误[:base]
account
#in shop.rb
validate :is_account
def is_account
if account == 1
limit = 10
elsif account == 2
limit = 50
else account == 3
limit = 100
end
errors.add(:base, "Reached maximum number of items for shop") if account == account && products.size >= limit
end
#in products_controller.rb
def new
if current_user.shop.nil?
flash[:alert] = I18n.t 'shops.create.must'
redirect_to :action => :index
elsif current_user.shop.invalid?
flash[:alert] = I18n.t 'shops.upgrade.must'
redirect_to :action => :index
else
@product = Product.new
end
end