6

I get

ActiveRecord::RecordNotFound: Couldn't find Client with ID=3 for Order with ID=

when trying to submit an Order form for an existing client. This happens through the form or the console by typing:

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

The reject_if idea came from here but I logged the method and it's not even being called! It doesn't matter what its name is!

Mayur Shah
  • 3,014
  • 1
  • 19
  • 38
manafire
  • 5,776
  • 3
  • 37
  • 50

4 Answers4

7

Note: Feb 2020

Since I'm starting to get downvotes on this 8 years later, adding this note. While this was the original solution I went with 8 years ago, a better one has been proposed by MatayoshiMariano (5 years after my OP).

My Original Fix

Fixed the issue by overloading the client_attributes= method, as described here:

  def client_attributes=(client_attrs)    
    self.client = Client.find_or_initialize_by_id(client_attrs.delete(:id))
    self.client.attributes = client_attrs
  end
manafire
  • 5,776
  • 3
  • 37
  • 50
  • Doesn't this end up creating another Client even if it finds a client by id? – dubilla Jul 02 '14 at 22:46
  • This is not the Rails way. The issue in the OP has existed for a decade and the solution is to use `client_id`. See https://github.com/rails/rails/issues/7256 Although I appreciate there may be value in this approach, I have learned from experience that sticking to the intended way for Rails to work has rewards and deviating brings lots of problems. So I strongly suggest using `client_id` and not overriding `client_attributes=`. – Jason Feb 02 '21 at 16:15
2

If you only want a new Order with an existing client, without modifying the client, you need to assign the id.

Order.new(client_id: 3)

This is another way to do this without overloading the client_attributes= method and cleanest

The new Order now has the client with ID 3

If you also want to update ant client's attributes you must add the client_attributes, for example:

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

See https://github.com/rails/rails/issues/7256 from 2012.

Jason
  • 10,225
  • 8
  • 57
  • 79
MatayoshiMariano
  • 1,616
  • 16
  • 22
  • 1
    This should be the accepted answer. The Rails way to solve the OP is to use `client_id`. So either 1) set `client_id` on the frontend before passing to the backend or 2) assign `client_id` to the id from the `client_attributes` on the backend. After either of these approaches, accepts_nested_attributes_for will work. – Jason Feb 02 '21 at 16:11
  • OK thanks. I've changed this to the accepted answer. – manafire Mar 02 '21 at 11:21
0

Had the same error creating a new Thing for existing model with has_many and belongs_to relations.

Fixed it by adding a hidden field for the id of the existing model, for instance User, to the form.

= form.input :user_id, as: :hidden

Then new Thing was created without the error.

Dende
  • 445
  • 6
  • 15
0

If you have has_many relationship, this will work. Tested on 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
Henry Jacob
  • 91
  • 1
  • 2