I have 4 tables: proposals, proposal_line_items (proposal_line_items is nested inside proposals) invoices,and invoice_line_items.
I am trying to feed rows created in the proposal_line_items table into invoices when the client approves of each item. I am using a checkbox ( 1 => approved) in the proposal_line_items to determine if it is approved or not.
This is how I set up my invoices controller to make the invoices receive the rows from proposal_line_items.
class InvoicesController < ActionController
def new
@approved_items = Proposal.find(params[:proposal_id]).proposal_line_items.where(:approved => 1)
end
end
When I try to create the new invoice I get the following error:
ActiveRecord::RecordNotFound in InvoicesController#new Couldn't find Proposal with 'id'= Extracted source (around line #17): 15 16 17 18 19 20
Controller action:
# GET /invoices/new
def new
@approved Proposal.find(params[:proposal_id]).proposal_line_items.where(:approved => 1)
end
Can you please help me solve this issue? Thank you!
Models:
class Proposal < ActiveRecord::Base
has_many :proposal_line_items
end
class ProposalLineItem < ActiveRecord::Base
belongs_to :proposal
end
class Invoice < ActiveRecord::Base
has_many :invoice_line_items
end
class InvoiceLineItem < ActiveRecord::Base
belongs_to :invoice
end
Migration files:
class CreateProposalLineItems < ActiveRecord::Migration
def change
create_table :proposal_line_items do |t|
t.references :proposal, index: true, foreign_key: true
t.string :name
t.integer :approved
t.timestamps null: false
end
end
end
class CreateProposals < ActiveRecord::Migration
def change
create_table :proposals do |t|
t.string :name
t.timestamps null: false
end
end
end
class CreateInvoiceLineItems < ActiveRecord::Migration
def change
create_table :invoice_line_items do |t|
t.references :invoice, index: true, foreign_key: true
t.string :name
t.integer :approved
t.timestamps null: false
end
end
end
class CreateInvoices < ActiveRecord::Migration
def change
create_table :invoices do |t|
t.string :name
t.timestamps null: false
end
end
end
routes.rb
invoices GET /invoices(.:format) invoices#index POST /invoices(.:format) invoices#create
new_invoice GET /invoices/new(.:format) invoices#new
edit_invoice GET /invoices/:id/edit(.:format) invoices#edit
invoice GET /invoices/:id(.:format) invoices#show
PATCH /invoices/:id(.:format) invoices#update
PUT /invoices/:id(.:format) invoices#update
DELETE /invoices/:id(.:format) invoices#destroy`
proposal_proposal_line_items POST /proposals/:proposal_id/proposal_line_items(.:format) proposals/proposal_line_items#create
new_proposal_proposal_line_item GET /proposals/:proposal_id/proposal_line_items/new(.:format) proposals/proposal_line_items#new
edit_proposal_proposal_line_item GET /proposals/:proposal_id/proposal_line_items/:id/edit(.:format) proposals/proposal_line_items#edit
proposal_proposal_line_item GET /proposals/:proposal_id/proposal_line_items/:id(.:format) proposals/proposal_line_items#show
PATCH /proposals/:proposal_id/proposal_line_items/:id(.:format) proposals/proposal_line_items#update
PUT /proposals/:proposal_id/proposal_line_items/:id(.:format) proposals/proposal_line_items#update
DELETE /proposals/:proposal_id/proposal_line_items/:id(.:format) proposals/proposal_line_items#destroy
proposals GET /proposals(.:format) proposals#index
POST /proposals(.:format) proposals#create
new_proposal GET /proposals/new(.:format) proposals#new
edit_proposal GET /proposals/:id/edit(.:format) proposals#edit
proposal GET /proposals/:id(.:format) proposals#show
PATCH /proposals/:id(.:format) proposals#update
PUT /proposals/:id(.:format) proposals#update
DELETE /proposals/:id(.:format) proposals#destroy
update
controller
class InvoicesController < ApplicationController
before_action :set_invoice, only: [:show, :edit, :update, :destroy]
# GET /invoices
# GET /invoices.json
def index
@invoices = Invoice.all
end
# GET /invoices/1
# GET /invoices/1.json
def show
end
# GET /invoices/new
def new
@approved = Proposal.require(:proposal_id).proposal_line_items.where(:approved => 1)
end
# GET /invoices/1/edit
def edit
end
# POST /invoices
# POST /invoices.json
def create
@invoice = Invoice.new(invoice_params)
respond_to do |format|
if @invoice.save
format.html { redirect_to @invoice, notice: 'Invoice was successfully created.' }
format.json { render :show, status: :created, location: @invoice }
else
format.html { render :new }
format.json { render json: @invoice.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /invoices/1
# PATCH/PUT /invoices/1.json
def update
respond_to do |format|
if @invoice.update(invoice_params)
format.html { redirect_to @invoice, notice: 'Invoice was successfully updated.' }
format.json { render :show, status: :ok, location: @invoice }
else
format.html { render :edit }
format.json { render json: @invoice.errors, status: :unprocessable_entity }
end
end
end
# DELETE /invoices/1
# DELETE /invoices/1.json
def destroy
@invoice.destroy
respond_to do |format|
format.html { redirect_to invoices_url, notice: 'Invoice was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_invoice
@invoice = Invoice.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def invoice_params
params.require(:invoice).permit(:date, :proposal_line_item_id)
end
end
UPDATE
New
<h1>New Invoice</h1>
<%= render 'form' %>
<%= link_to 'Back', invoices_path %>
Form
%= form_for(@invoice) do |f| %>
<% if @invoice.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@invoice.errors.count, "error") %> prohibited this invoice from being saved:</h2>
<ul>
<% @invoice.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :date %><br>
<%= f.datetime_select :date %>
</div>
<div class="field">
<%= f.label :proposal_line_item %><br>
<%= collection_select( :proposal_line_item, :proposal_line_item_id, Proposal_line_item.all, :id, :date, {}, {:multiple => false}) %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Log Output
Started GET "/invoices/new" for ::1 at 2015-04-09 12:48:00 -0500
Processing by InvoicesController#new as HTML
Completed 400 Bad Request in 1ms
ActionController::ParameterMissing (param is missing or the value is empty: proposal_line_item):
app/controllers/invoices_controller.rb:23:in `proposal_line_item'
app/controllers/invoices_controller.rb:17:in `new'
Rendered /Users/davefogo/.rbenv/versions/2.1.3/lib/ruby/gems/2.1.0/gems/actionpack-4.2.0/lib/action_dispatch/middleware/templates/rescues/_source.erb (4.6ms)
Rendered /Users/davefogo/.rbenv/versions/2.1.3/lib/ruby/gems/2.1.0/gems/actionpack-4.2.0/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (1.8ms)
Rendered /Users/davefogo/.rbenv/versions/2.1.3/lib/ruby/gems/2.1.0/gems/actionpack-4.2.0/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (0.6ms)
Rendered /Users/davefogo/.rbenv/versions/2.1.3/lib/ruby/gems/2.1.0/gems/actionpack-4.2.0/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout (16.6ms)
Rendered /Users/davefogo/.rbenv/versions/2.1.3/lib/ruby/gems/2.1.0/gems/web-console-2.1.0/lib/web_console/templates/_markup.html (0.2ms)
Rendered /Users/davefogo/.rbenv/versions/2.1.3/lib/ruby/gems/2.1.0/gems/web-console-2.1.0/lib/web_console/templates/style.css within layouts/inlined_string (0.2ms)
Rendered /Users/davefogo/.rbenv/versions/2.1.3/lib/ruby/gems/2.1.0/gems/web-console-2.1.0/lib/web_console/templates/_inner_console_markup.html within layouts/inlined_string (0.2ms)
Rendered /Users/davefogo/.rbenv/versions/2.1.3/lib/ruby/gems/2.1.0/gems/web-console-2.1.0/lib/web_console/templates/_prompt_box_markup.html within layouts/inlined_string (0.2ms)
Rendered /Users/davefogo/.rbenv/versions/2.1.3/lib/ruby/gems/2.1.0/gems/web-console-2.1.0/lib/web_console/templates/console.js within layouts/javascript (11.0ms)
Rendered /Users/davefogo/.rbenv/versions/2.1.3/lib/ruby/gems/2.1.0/gems/web-console-2.1.0/lib/web_console/templates/main.js within layouts/javascript (0.3ms)
Rendered /Users/davefogo/.rbenv/versions/2.1.3/lib/ruby/gems/2.1.0/gems/web-console-2.1.0/lib/web_console/templates/error_page.js within layouts/javascript (0.5ms)
Rendered /Users/davefogo/.rbenv/versions/2.1.3/lib/ruby/gems/2.1.0/gems/web-console-2.1.0/lib/web_console/templates/index.html (24.2ms)
Started GET "/invoices/new" for ::1 at 2015-04-09 12:48:00 -0500
Processing by InvoicesController#new as HTML
Completed 400 Bad Request in 1ms
ActionController::ParameterMissing (param is missing or the value is empty: proposal_line_item):
app/controllers/invoices_controller.rb:23:in `proposal_line_item'
app/controllers/invoices_controller.rb:17:in `new'
Rendered /Users/davefogo/.rbenv/versions/2.1.3/lib/ruby/gems/2.1.0/gems/actionpack-4.2.0/lib/action_dispatch/middleware/templates/rescues/_source.erb (4.5ms)
Rendered /Users/davefogo/.rbenv/versions/2.1.3/lib/ruby/gems/2.1.0/gems/actionpack-4.2.0/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (1.8ms)
Rendered /Users/davefogo/.rbenv/versions/2.1.3/lib/ruby/gems/2.1.0/gems/actionpack-4.2.0/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (0.6ms)
Rendered /Users/davefogo/.rbenv/versions/2.1.3/lib/ruby/gems/2.1.0/gems/actionpack-4.2.0/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout (25.6ms)
Rendered /Users/davefogo/.rbenv/versions/2.1.3/lib/ruby/gems/2.1.0/gems/web-console-2.1.0/lib/web_console/templates/_markup.html (0.2ms)
Rendered /Users/davefogo/.rbenv/versions/2.1.3/lib/ruby/gems/2.1.0/gems/web-console-2.1.0/lib/web_console/templates/style.css within layouts/inlined_string (0.2ms)
Rendered /Users/davefogo/.rbenv/versions/2.1.3/lib/ruby/gems/2.1.0/gems/web-console-2.1.0/lib/web_console/templates/_inner_console_markup.html within layouts/inlined_string (0.2ms)
Rendered /Users/davefogo/.rbenv/versions/2.1.3/lib/ruby/gems/2.1.0/gems/web-console-2.1.0/lib/web_console/templates/_prompt_box_markup.html within layouts/inlined_string (0.2ms)
Rendered /Users/davefogo/.rbenv/versions/2.1.3/lib/ruby/gems/2.1.0/gems/web-console-2.1.0/lib/web_console/templates/console.js within layouts/javascript (11.0ms)
Rendered /Users/davefogo/.rbenv/versions/2.1.3/lib/ruby/gems/2.1.0/gems/web-console-2.1.0/lib/web_console/templates/main.js within layouts/javascript (0.2ms)
Rendered /Users/davefogo/.rbenv/versions/2.1.3/lib/ruby/gems/2.1.0/gems/web-console-2.1.0/lib/web_console/templates/error_page.js within layouts/javascript (0.3ms)
Rendered /Users/davefogo/.rbenv/versions/2.1.3/lib/ruby/gems/2.1.0/gems/web-console-2.1.0/lib/web_console/templates/index.html (23.8ms)
The issue here is that you are making a request to a route with no parameters. I incorrectly assumed that you were seeing this error when you were submitting the form, you are seeing this error when the form is rendered. I would suggest updating the route from /invoices/new
to something along the lines of /proposal/:proposal_id/invoices/new
and then using this for your controller method:
class InvoicesController < ActionController
def new
@approved_items = Proposal.find(params.require(:proposal_id)).proposal_line_items.where(:approved => 1)
end
end
You can then use your original view before I suggested modifications.
Everything below this line is wrong
The issue here is that you are trying to query a Proposal
, but the item you are actually passing in to the controller from your form is a ProposalLineItem
On this line of your form:
collection_select( :proposal_line_item, :proposal_line_item_id, Proposal_line_item.all, :id, :date, {}, {:multiple => false})
You are generating a collection of ProposalLineItem
s for your form, but there is also a typo in that line of Proposal_line_item
instead of ProposalLineItem
In order to query a Proposal
in your controller, you need to do one of two things.
Option 1
Update your controller to this:
class InvoicesController < ActionController
def new
@approved_items = proposal ? proposal.proposal_line_items.where(approved: 1) : []
end
protected
def proposal_line_item
# The way you have your form configured, the params hash will look like this: {"proposal_line_item" => {"proposal_line_item_id" => "some_id"}}
@_proposal_line_item = ProposalLineItem.find(params.require(:proposal_line_item).require(:proposal_line_item_id))
end
def proposal
proposal_line_item.proposal
end
end
Option 2
However given the context of the form, and what your controller is trying to do, it might make more sense to render a collection of Proposal
s instead of ProposalLineItem
s. Perhaps something like this:
# in your form
collection_select( :proposal, :proposal_id, Proposal.all, :id, :name, {}, {:multiple => false})
And then in your controller:
class InvoicesController < ActionController
def new
@approved_items = proposal.proposal_line_items.where(approved: 1)
end
protected
def proposal
Proposal.find(params.require(:proposal).require(:proposal_id))
end
end
Obviously the choice is yours here, but given what it looks like you are trying to do, I would lean towards option 2.
Also FYI, if you want to test out the parameters stuff in a rails console, you will want to do this:
> params = ActionController::Parameters.new
=> {}
> params[:proposal_line_item] = {}
=> {}
> params[:proposal_line_item][:proposal_line_item_id] = "asdf"
=> "asdf"
> params.require(:proposal_line_item)
=> {"proposal_line_item_id"=>"asdf"}
> params.require(:proposal_line_item).require(:proposal_line_item_id)
=> "asdf"