首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Rails有许多带有接受嵌套属性的验证唯一属性。

Rails有许多带有接受嵌套属性的验证唯一属性。
EN

Stack Overflow用户
提问于 2022-11-11 15:20:37
回答 2查看 51关注 0票数 0

我有许多发票线项目的发票。发票行项目指向特定项目。在创建或更新发票时,我希望验证同一项(项目ID)的发票行项目不超过一个。我使用的是接受嵌套属性和嵌套表单。

我知道validates_uniqueness_of item_id: {scope: invoice_id}的事

然而,我无法让它在我的生活中正常工作。这是我的代码:

发票线项目

代码语言:javascript
复制
belongs_to :item

validates_uniqueness_of :item_id, scope: :invoice_id

发票

代码语言:javascript
复制
has_many :invoice_line_items, dependent: :destroy
accepts_nested_attributes_for :invoice_line_items, allow_destroy: true

发票控制器

代码语言:javascript
复制
  // strong params
  params.require(:invoice).permit(
    :id,
    :description, 
    :company_id, 
    invoice_line_items_attributes: [
      :id,
      :invoice_id,
      :item_id,
      :quantity,
      :_destroy
    ]
  )
  // ...
  // create action
  def create
    @invoice = Invoice.new(invoice_params)

    respond_to do |format|
      if @invoice.save
         
        format.html { redirect_to @invoice }
      else
        format.html { render action: 'new' }
      end
    end
  end

控制器代码是相当标准的( rails支架创建的)。

UPDATE --请注意,在进行更多诊断之后,我发现在create上总是允许我在第一次创建发票和编辑发票而不修改行项的情况下使用相同的项创建多个行项,但在编辑发票和尝试添加具有相同项的另一个行项或修改行项的属性时则不允许这样做。这似乎是我不理解rails如何处理嵌套验证的问题。

UPDATE 2如果我添加validates_associated :invoice_line_items,它只解决编辑已经创建的发票而不修改属性时的问题。不管修改了什么,它似乎都强制进行验证检查。然而,它在使用_destroy时会出现问题。

更新3添加了控制器代码。

问题--如何使用嵌套形式验证模型上的属性有许多记录,并接受嵌套属性?

EN

回答 2

Stack Overflow用户

发布于 2022-11-14 17:28:51

我知道这不是直接回答你的问题,但我会做一些不同的事情。

InvoiceLineItem存在的唯一原因是将一个Invoice与多个Item相关联。

与其拥有一堆用于InvoiceLineItem的数据库记录,不如考虑一个字段(例如HSTORE或JSONB),它直接将Item存储到Invoice

代码语言:javascript
复制
> @invoice.item_hash
> { #item1: #quantity1, #item2: #quantity2, #item3: #quantity3, ... }

在哈希中使用:item_id作为键将防止默认情况下的重复值。

一个简单的实现是使用ActiveRecord::Store,这涉及到使用文本字段和让Rails处理数据的序列化。

Rails还支持Postgresql和JSON和JSONB中的HstoreMySQL 5.7+中的JSON数据类型。

查找将更快,因为您不需要遍历InvoiceLineItem才能在InvoiceItem之间穿行。还有关于与JSONB列交互的地段 of 太棒了 资源

代码语言:javascript
复制
# invoice.rb
...
def items
  Item.find( item_hash.keys)
end

获得“引用此项目的发票”有点不直观,但仍然很有可能(而且很快):

代码语言:javascript
复制
# item.rb
...
# using a Postgres JSON query operator:
# jsonb ? text → boolean (Does the text string exist as a top-level key or array element within the JSON value?)
# https://www.postgresql.org/docs/current/functions-json.html#FUNCTIONS-JSONB-OP-TABLE
def invoices
  Invoice.where('item_hash ? :key', key: id)
end
票数 0
EN

Stack Overflow用户

发布于 2022-11-16 00:36:26

在读了几遍之后,我认为它是:

发票上有许多invoice_line_items

发票通过invoice_line_items有许多项目

Item_id需要对每个发票都是唯一的,因此不能重复line_item列表中的项目。

物品是可以在多张发票中显示的物品目录。例如,项目是像widget_one和widget_two这样的东西,发票只能包含小部件一行,但是许多发票可以包含相同的项目。如果这不是真的,而且一个项目只会出现在一张发票中,请告诉我,我会更改代码。

因此,我认为您的验证不应该在项目,因为项目不知道发票。您希望确保您的join表在给定的invoice_id有重复item_id条目的地方没有条目。

item.rb:

代码语言:javascript
复制
has_many :invoice_line_items
has_many :invoices, through: :invoice_line_items

invoice.rb:

代码语言:javascript
复制
has_many :invoice_line_items
has_many :items, through: :invoice_line_items

invoice_line_item.rb:

代码语言:javascript
复制
belongs_to :item
belongs_to :invoice
validates_uniqueness_of :item_id, :scope => :invoice_id

这应该能满足你的需要。当您创建一个新的发票并保存它时,Rails应该尝试保存每个行项和联接表。当它命中重复的item_id时,它会失败并抛出一个错误。

如果您要在代码中有唯一的约束,我会在数据库中使用一个约束进行回退,这样如果您做了一些使结束运行在这段代码周围的事情,那么它仍然会失败。因此,应该添加迁移来执行以下操作:

add_uniq_constraint_to_invoice_line_items.rb:

代码语言:javascript
复制
def change
  add_index :invoice_line_items, [:invoice_id, :item_id], unique: true    
end

此索引将阻止创建这两列相同的记录。

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

https://stackoverflow.com/questions/74404627

复制
相关文章

相似问题

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