【问题标题】:RecordNotFound with accepts_nested_attributes_for and belongs_toRecordNotFound 与accepts_nested_attributes_for 和belongs_to
【发布时间】:2012-03-25 22:03:51
【问题描述】:

我明白了

ActiveRecord::RecordNotFound:对于 ID=3 的订单,找不到 ID=3 的客户端

尝试为现有客户提交订单时。这通过表单或控制台输入:

Order.new(:client_attributes => { :id => 3 })

payment_form.html.erb

<%= semantic_form_for @order, :url => checkout_purchase_url(:secure => true) do |f| %>

        <%= f.inputs "Personal Information" do %>

            <%= f.semantic_fields_for :client do |ff| %>
                <%= ff.input :first_name %>
                <%= ff.input :last_name %>              
                <!-- looks like semantic_fields_for auto-inserts a hidden field for client ID -->
            <% end %>

        <% end %>
<% end %>

Order.rb

class Order < ActiveRecord::Base
  belongs_to :client
  accepts_nested_attributes_for :client, :reject_if => :check_client

  def check_client(client_attr)
    if _client = Client.find(client_attr['id'])
      self.client = _client
      return true
    else
      return false
    end    
  end
end

reject_if 的想法来自here,但我记录了该方法,但它甚至没有被调用!不管它叫什么名字!

【问题讨论】:

    标签: ruby-on-rails nested-forms nested-attributes


    【解决方案1】:

    注意:2020 年 2 月

    由于我在 8 年后开始对此表示反对,因此添加了此注释。虽然这是我 8 年前使用的原始解决方案,a better one has been proposed by MatayoshiMariano(在我的 OP 5 年后)。

    我的原始修复

    通过重载 client_attributes= 方法修复了该问题,如here 所述:

      def client_attributes=(client_attrs)    
        self.client = Client.find_or_initialize_by_id(client_attrs.delete(:id))
        self.client.attributes = client_attrs
      end
    

    【讨论】:

    • 即使通过 id 找到客户端,这最终不会创建另一个客户端吗?
    • 这不是 Rails 的方式。 OP 中的问题已经存在了十年,解决方案是使用client_id。请参阅github.com/rails/rails/issues/7256 虽然我很欣赏这种方法可能有价值,但我从经验中了解到,坚持 Rails 的预期工作方式会带来回报,而偏离会带来很多问题。所以我强烈建议使用client_id 而不是覆盖client_attributes=
    【解决方案2】:

    如果你只想要一个带有现有客户端的新订单,而不修改客户端,你需要分配 id。

    Order.new(client_id: 3)
    

    这是另一种无需重载client_attributes= 方法且最干净的方法

    新订单现在拥有 ID 为 3 的客户

    如果您还想更新ant客户端的属性,您必须添加client_attributes,例如:

    Order.new(client_id: 3, client_attributes: { id: 3, last_order_at: Time.current })
    

    请参阅 2012 年的 https://github.com/rails/rails/issues/7256

    【讨论】:

    • 这应该是公认的答案。 Rails 解决 OP 的方法是使用client_id。因此,要么 1) 在传递到后端之前在前端设置 client_id,要么 2) 将 client_id 分配给后端 client_attributes 的 id。在这两种方法中的任何一种之后,accepts_nested_attributes_for 都会起作用。
    • 好的,谢谢。我已将此更改为已接受的答案。
    【解决方案3】:

    如果你有 has_many 关系,这将起作用。在 Rails 6.0.2 上测试

      def clients_attributes =(attributes)
        # Get IDs for any clients that already exist.
        client_ids = attributes.values.map { |a| a[:id] }.compact
    
        # Now find them all and move them to this section.
        clients << Client.find(client_ids)
    
        # Update them with standard `accepts_nested_attributes_for` behaviour.
        super attributes
      end
    

    【讨论】:

      【解决方案4】:

      为具有 has_manybelongs_to 关系的现有模型创建新事物时出现相同的错误。

      通过在表单中​​为现有模型(例如用户)的 id 添加一个隐藏字段来修复它。

      = form.input :user_id, as: :hidden
      

      然后新事物被创建而没有错误。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-25
        • 1970-01-01
        • 2022-07-08
        相关资源
        最近更新 更多