child forms, not nested

Hi,

I'm trying to create forms for child objects that are separate from
the parent objects but that preserve the relation. I have this as my
controller methods but when I submit the "new" form it says :

Couldn't find Inventory without an ID

Can you please help?

  def new
    @order = @inventory.orders.build
  end

  def create
    @order = Order.new(params[:order])
    @order.inventory_id = params[:inventory_id]

    respond_to do |format|
      if @order.save
        flash[:success] = 'Order created successfully'
        logger.debug " order saved successfully"
        format.html { redirect_to
inventory_path(@order.inventory_id) }
      else
        logger.debug " order not saved"
        format.html { render :action => "new" }
      end
    end

  end

  def get_inventory
    @inventory = Inventory.find(params[:inventory_id])
  end

I’m not sure if I understood you correctly. I assume you have a route like this:

resources :inventories do

resources :orders

end

If so you could use a before filter to automatically load the inventory in your OrdersController before every action like this:

class OrdersController < ApplicationController

def inventory

@inventory ||= Inventory.find(params[:inventory_id])

end

before_filter :inventory

def new

@order = inventory.orders.build

end

def create

@order = inventory.order.build(params[:order])

if @order.save

flash[:success] = ‘Order created successfully’

logger.debug " order saved successfully"

redirect_to inventory

else

logger.debug " order not saved"

render :new

end

end

end

As you can see I simplified your create Action, since you don’t use anything else than html in the response you can skip the respond_to. redirect_to inventory is short for redirect_to inventory_path(inventory), and render :new is a shortcut for render :action => 'new'.

I hope I could help, if not please don’t hesitate to ask again.

Regards, Jens

@order = inventory.order.build(params[:order])

should be

@order = inventory.orders.build(params[:order])

Oh, I should have mentioned that I'm using Rails 2.3.5. I'm not sure
if that makes a difference?
I'll try out what you suggested, thanks!

The routes description is different in rails 2.3.5

map.resources :inventories do |inventory|

inventory.resources :orders

end

The rest should work as described.

hmm now I get Only get, put, and delete requests are allowed.

This is in my routes:

  map.resources :inventories do |inventory|
    inventory.resources :orders
  end
  map.resources :orders

And this is my controller:

  before_filter :login_required, :get_inventory

  def new
    @order = @inventory.orders.build
  end

  def create
    @order = @inventory.orders.build(params[:order])

    if @order.save
        flash[:success] = 'Order created successfully'
        logger.debug "order saved successfully"
        redirect_to @inventory
    else
        logger.debug "order not saved"
        render :new
    end

  end

  def get_inventory
    @inventory = Inventory.find(params[:inventory_id])
  end
end

  1. can you post the full error message and what you did to get it

def get_inventory
@inventory = Inventory.find(params[:inventory_id])
end

should_be

def inventory
@inventory ||= Inventory.find(params[:inventory_id])
end

the the Inventory is cached if you need it multiple time during one request. Leaving the get_ is more like ruby and rails work on attribute accessors. And if you cache the inventory you can get rid of the @ in front of any other call to the inventory, just use the defined accessor method.

You can even get rid of the before filter if you use the inventory accessor, so the inventory only get’s loaded if you really need it.

ok I made the change number 2.

THis is the full trace:

/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/actionpack-2.3.5/lib/action_controller/routing/
recognition_optimisation.rb:64:in `recognize_path'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/actionpack-2.3.5/lib/action_controller/routing/
route_set.rb:441:in `recognize'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/actionpack-2.3.5/lib/action_controller/routing/
route_set.rb:436:in `call'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/actionpack-2.3.5/lib/action_controller/dispatcher.rb:
87:in `dispatch'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/actionpack-2.3.5/lib/action_controller/dispatcher.rb:
121:in `_call'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/actionpack-2.3.5/lib/action_controller/dispatcher.rb:
130:in `build_middleware_stack'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/activerecord-2.3.5/lib/active_record/query_cache.rb:
29:in `call'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/activerecord-2.3.5/lib/active_record/query_cache.rb:
29:in `call'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/activerecord-2.3.5/lib/active_record/connection_adapters/
abstract/query_cache.rb:34:in `cache'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/activerecord-2.3.5/lib/active_record/query_cache.rb:9:in
`cache'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/activerecord-2.3.5/lib/active_record/query_cache.rb:
28:in `call'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/activerecord-2.3.5/lib/active_record/connection_adapters/
abstract/connection_pool.rb:361:in `call'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/actionpack-2.3.5/lib/action_controller/
string_coercion.rb:25:in `call'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/rack-1.0.1/lib/rack/head.rb:9:in `call'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/rack-1.0.1/lib/rack/methodoverride.rb:24:in `call'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/actionpack-2.3.5/lib/action_controller/params_parser.rb:
15:in `call'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/actionpack-2.3.5/lib/action_controller/session/
cookie_store.rb:93:in `call'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/actionpack-2.3.5/lib/action_controller/failsafe.rb:26:in
`call'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/rack-1.0.1/lib/rack/lock.rb:11:in `call'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/rack-1.0.1/lib/rack/lock.rb:11:in `synchronize'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/rack-1.0.1/lib/rack/lock.rb:11:in `call'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/actionpack-2.3.5/lib/action_controller/dispatcher.rb:
114:in `call'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/actionpack-2.3.5/lib/action_controller/reloader.rb:34:in
`run'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/actionpack-2.3.5/lib/action_controller/dispatcher.rb:
108:in `call'
/Users/e/.gem/ruby/1.8/gems/rails-2.3.5/lib/rails/rack/static.rb:31:in
`call'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/rack-1.0.1/lib/rack/urlmap.rb:46:in `call'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/rack-1.0.1/lib/rack/urlmap.rb:40:in `each'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/rack-1.0.1/lib/rack/urlmap.rb:40:in `call'
/Users/e/.gem/ruby/1.8/gems/rails-2.3.5/lib/rails/rack/log_tailer.rb:
17:in `call'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/rack-1.0.1/lib/rack/content_length.rb:13:in `call'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/rack-1.0.1/lib/rack/chunked.rb:15:in `call'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/rack-1.0.1/lib/rack/handler/mongrel.rb:64:in `process'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/mongrel-1.1.5/lib/mongrel.rb:159:in `process_client'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/mongrel-1.1.5/lib/mongrel.rb:158:in `each'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/mongrel-1.1.5/lib/mongrel.rb:158:in `process_client'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/mongrel-1.1.5/lib/mongrel.rb:285:in `run'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/mongrel-1.1.5/lib/mongrel.rb:285:in `initialize'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/mongrel-1.1.5/lib/mongrel.rb:285:in `new'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/mongrel-1.1.5/lib/mongrel.rb:285:in `run'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/mongrel-1.1.5/lib/mongrel.rb:268:in `initialize'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/mongrel-1.1.5/lib/mongrel.rb:268:in `new'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/mongrel-1.1.5/lib/mongrel.rb:268:in `run'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
gems/1.8/gems/rack-1.0.1/lib/rack/handler/mongrel.rb:34:in `run'
/Users/e/.gem/ruby/1.8/gems/rails-2.3.5/lib/commands/server.rb:111
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
1.8/rubygems/custom_require.rb:31:in `gem_original_require'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/
1.8/rubygems/custom_require.rb:31:in `require'

I was on /inventories/4000/orders/new page and click "submit" to
create a new order before getting the error message.

sorry, but I can’t work with this error, can you post some more info from the logfile around this error, especially the request log.

and can you show me the code of the form in the orders#new view

This is the new view for the order:

<%= error_messages_for :order %>

<% form_for :order do |f| -%>
<p><%= label_tag 'Quantity Requested by order:' %><br/>
<%= f.text_field :qty_requested %></p>
<%= f.hidden_field :inventory_id, :value=>@inventory.inventory_id %>
<p><% if !@inventory.nil?%><%= submit_tag 'Submit', :id =>
@inventory.inventory_id %></p><% end %>
<% end %>

and these are the errors in the log file:

Processing OrdersController#new (for 127.0.0.1 at 2011-05-06 15:25:27)
[POST]
  Parameters: {"commit"=>"Submit",
"authenticity_token"=>"bkIEWE9A5XNqPxE3Hv0et3R4NgHHqLi6D99SYSn8ZkQ=",
"order"=>{"qty_requested"=>"123"}}
  e[4;35;1mAdminUser Columns (2.1ms)e[0m e[0mSHOW FIELDS FROM
`admin_users`e[0m
  e[4;36;1mAdminUser Load (0.3ms)e[0m e[0;1mSELECT * FROM
`admin_users` WHERE (`admin_users`.`id` = 39) LIMIT 1e[0m
  e[4;35;1mOrder Columns (2.4ms)e[0m e[0mSHOW FIELDS FROM
`orders`e[0m

ActiveRecord::RecordNotFound (Couldn't find Inventory without an ID):
  app/controllers/orders_controller.rb:37:in `new'

Rendered rescues/_trace (34.9ms)
Rendered rescues/_request_and_response (0.5ms)
Rendering rescues/layout (not_found)
  e[4;36;1mSQL (0.1ms)e[0m e[0;1mSET SQL_AUTO_IS_NULL=0e[0m

You can try

<% form_for [@inventory, @order] do |f| -%>

this will create the correct url (<form action="/inventories/4000/orders method=“post”>). And you can get rid of the hidden field with the inventory_id.

why do you have if !@inventory around your submit tag? If the form is only available with the nested resource url, than it should be always available.

oh my, putting

form_for [@inventory, @order]

worked.
Thanks a million!!