将数据库模型转换为 Ruby On Rails 上的模型

Posted

技术标签:

【中文标题】将数据库模型转换为 Ruby On Rails 上的模型【英文标题】:Translating Database Models to Models on Ruby On Rails 【发布时间】:2018-05-27 23:17:03 【问题描述】:

我在学校通过购买/转售平台项目开始使用 Ruby On Rails。当我尝试从关系模型中翻译模型时,我遇到了问题。

首先,我已经为我的数据库建模。这是简化的实体关系模型:

然后我将它翻译成关系模型:

最后,我在 Ruby On Rails 中实现了它。

我已经实现了一个模型客户端:

class Client < ApplicationRecord
    attr_accessor :name

    validates :name, :presence => true

    has_many :purchasings, :dependent => :destroy

    has_many :sellers, :through => :purchasings
    has_many :articles, :through => :purchasings
end

我已经实现了一个模型卖方:

class Seller < ApplicationRecord
    attr_accessor :name

    validates :name, :presence => true

    has_many :purchasings, :dependent => :destroy

    has_many :sellers, :through => :purchasings
    has_many :articles, :through => :purchasings
end

我已经实现了一篇示范文章

class Article < ApplicationRecord
    attr_accessor :quantity

    validates :quantity, :presence => true

    has_one :purchasing, :dependent => :destroy

    has_one :client, :through => :purchasings
    has_one :seller, :through => :purchasings
end

我已经实现了一个模型采购:

class Purchasing < ApplicationRecord
    attr_accessor :client_id, :seller_id, :article_id

    belongs_to :client, :class_name => "Client"
    belongs_to :seller, :class_name => "Seller"
    belongs_to :article, :class_name => "Article"

    validates :client_id, :presence => true
    validates :seller_id, :presence => true
    validates :article_id, :presence => true
end

我已经修改了采购数据库迁移:

class CreatePurchasing < ActiveRecord::Migration[5.1]
    def change
        [...]

        add_index :purchasings, :client_id
        add_index :purchasings, :seller_id
        add_index :purchasings, :article_id
        add_index :purchasings, [:client_id, :seller_id], :unique => true
    end

    def down
        [...]
    end
end

我知道这是不正确的,因为当我在 Rails 控制台上执行以下代码时:

cl1 = Client.create(:name => "John")
cl2 = Client.create(:name => "James")
sel1 = Seller.create(:nom => "Jack")
sel2 = Seller.create(:nom => "Jil")
a1 = Article.create(:quantity => 5)

p1 = Purchasing.new(:client => cl1, :client_id => cl1.id, :seller => sel1, :seller_id => sel1.id, :article => a1, :article_id => a1.id)
p1.save
p2 = Purchasing.new(:client => cl2, :client_id => cl2.id, :seller => sel1, :seller_id => sel1.id, :article => a1, :article_id => a1.id)
p2.save

p2.save 返回 true,而文章不能由同一个卖家出售并由两个不同的客户购买。

【问题讨论】:

有问题吗? 另外,删除 attr_accessors。他们没有做你认为他们做的事。 @SergioTulentsev 好吧,我的测试没有产生我期望的结果,所以我正在寻找一种解决方案,以便获得正确的行为(p2.save 返回 false,因为该文章已经被客户)。 @SergioTulentsev 你能更准确地了解 atr_accessors 吗?我的理解是 attr_accessors 相当于在Java中声明getter/setter? “等同于在 Java 中声明 getter/setter”——正确,但在这里会适得其反。您的模型中不需要它们。声明它们会覆盖活动记录生成的 getter/setter。因此,这些属性不会被持久化。 【参考方案1】:

您在采购表的不正确列上添加索引。根据要求,article_id 和 Seller_id 最好不要重复。所以你实际上需要的是对seller_id 和article_id 列的唯一性约束。您可以通过在数据库层上的两列seller_id 和文章id 的组合上创建唯一索引来实现。您还应该在购买模型上添加应用层验证。

class Purchasing < ApplicationRecord
attr_accessor :client_id, :seller_id, :article_id

belongs_to :client, :class_name => "Client"
belongs_to :seller, :class_name => "Seller"
belongs_to :article, :class_name => "Article"

validates :client_id, :presence => true
validates :seller_id, :presence => true
validates :article_id, :presence => true

validates :article_id, uniqueness: scope: :seller_id
end

现在您还应该编写一个数据库迁移来为这两列添加唯一索引。

    class AddUniquenessConstraintInPurshasing < ActiveRecord::Migration
       def change
         add_index :purchasings, [:article_id, :seller_id], :unique => true
    end

结束

【讨论】:

感谢您的详细解答。 validates :article_id, uniqueness: scope: :seller_id 解释了article_id 对于给定的seller_id 是唯一的这一事实。我理解对了吗? 满足同一个卖家不分商品数量不能销售同一个商品的需求。此验证不允许您在购买表中有任何重复的 article_id 和 Seller_id 对。所以我宁愿说一个卖家只能卖一次特定的物品。如果你的要求不同,你的设计也应该改变。希望对您有所帮助! 感谢您的回答。它澄清了一切。最后,我想我应该像你说的那样更新我的模型,它不是那么相关

以上是关于将数据库模型转换为 Ruby On Rails 上的模型的主要内容,如果未能解决你的问题,请参考以下文章

将重复的SQL模型复制到Ruby on Rails postgresql模型中

Ruby on rails Haversine gem:将计算距离转换为公里

Ruby on Rails,将项目范围的单引号转换为双引号

Ruby on Rails:获取模型中的下一项

Ruby On Rails 很慢...?

如何使用 json 文件在 ruby​​ on rails 中填充模型(数据库)?