如何将行从一个模型提供给另一个模型?

时间:2015-04-07 15:40:12

标签: ruby-on-rails ruby activerecord models

我有4个表:提案,proposal_line_items(proposal_line_items嵌套在提案中)发票和invoice_line_items。

我正在尝试在客户审批每个项目时将在proposal_line_items表中创建的行提供给发票。我在proposal_line_items中使用了一个复选框(1 => approved)来确定它是否已获批准。

这是我设置发票控制器以使发票从proposal_line_items接收行的方式。

class InvoicesController < ActionController
  def new
    @approved_items = Proposal.find(params[:proposal_id]).proposal_line_items.where(:approved => 1)
  end
end

当我尝试创建新发票时,我收到以下错误:

ActiveRecord::RecordNotFound in InvoicesController#new Couldn't find Proposal with 'id'= Extracted source (around line #17): 15 16 17 18 19 20 

控制器操作:

# GET /invoices/new 
def new
  @approved Proposal.find(params[:proposal_id]).proposal_line_items.where(:approved => 1) 
end
你能帮我解决这个问题吗?谢谢!

型号:

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

迁移文件:

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

更新

控制器

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

更新

<h1>New Invoice</h1>
<%= render 'form' %>
<%= link_to 'Back', invoices_path %>

表格

%= 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 %>

日志输出

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)

1 个答案:

答案 0 :(得分:1)

这里的问题是您正在向没有参数的路线发出请求。我错误地认为您在提交表单时看到此错误,在呈现表单时您会看到此错误。我建议将路由从/invoices/new更新为/proposal/:proposal_id/invoices/new行,然后将其用于控制​​器方法:

class InvoicesController < ActionController
  def new
    @approved_items = Proposal.find(params.require(:proposal_id)).proposal_line_items.where(:approved => 1)
  end
end

然后,在我建议修改之前,您可以使用原始视图。

此行以下的所有内容均为错误

此处的问题是您尝试查询Proposal,但您实际从表单传入控制器的项目是ProposalLineItem

在表格的这一行:

collection_select( :proposal_line_item, :proposal_line_item_id, Proposal_line_item.all, :id, :date, {}, {:multiple => false})

您正在为表单生成ProposalLineItem个集合,但在Proposal_line_item而不是ProposalLineItem

行中也有拼写错误

要查询控制器中的Proposal,您需要执行以下两项操作之一。

选项1

将您的控制器更新为:

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

选项2

但是考虑到表单的上下文以及控制器尝试执行的操作,渲染Proposal s而不是ProposalLineItem s的集合可能更有意义。也许是这样的:

# in your form
collection_select( :proposal, :proposal_id, Proposal.all, :id, :name, {}, {:multiple => false})

然后在你的控制器中:

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

显然选择权在这里,但考虑到你想做的事情,我会倾向于选择2。

另外,仅供参考,如果您想在rails控制台中测试参数内容,您需要这样做:

> 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"