如何在rails 4上的ruby中从父对象创建嵌套子节点

我尝试在Rails 4中重现一个在Rails 3中工作正常的function:使用new_parent_child_path(@parent)从其父级的Show视图创建子记录。

不幸的是,当我validation子项创建时,我收到一条消息,指出child.parent_id field cannot be null 。 阅读时,看起来这个new_parent_child_path(@parent)function确实很难使用。 以下是我的代码的一部分……

楷模:

 class BusinessArea  "User", :foreign_key => "owner_id" # helps retrieving the owner name belongs_to :status, :class_name => "Parameter", :foreign_key => "status_id" # helps retrieving the status name has_many :business_flows end class BusinessFlow  "User", :foreign_key => "owner_id" # helps retrieving the owner name belongs_to :status, :class_name => "Parameter", :foreign_key => "status_id" # helps retrieving the status name has_many :business_processes belongs_to :business_area end 

路线:

 ODQStep1::Application.routes.draw do #static pages get '/help', to: "static_pages#help" get '/about', to: "static_pages#about" get '/contact', to: "static_pages#contact" get '/home', to: "static_pages#home" #root definition root to: "static_pages#home" resources :sessions, only: [:new, :create, :destroy] get '/signin', to: 'sessions#new' , via: :get match '/signout', to: 'sessions#destroy', via: :delete resources :parameters resources :business_areas do resources :business_flows, :only=>[:new, :create] end end 

创建子业务流的链接位于Business Area Show视图的末尾:

  

Business area:

  • |
  • |
<!--

-->
Name:
Code:
Status:
Description:
Hierarchy:
PCF index:
PCF reference:
Unique id:
Created by:
Playground id:
Created at:
Owner:
Updated by:
updated at:

Linked Business Flows

业务流程表

   

prohibited this business_flow from being saved:

Name:
"span8" %>
Code:
Status:
Description:
5, :class => "span8" %>
Hierarchy:
PCF index:
PCF reference:

业务流程控制器

 class BusinessFlowsController < ApplicationController # Check for active session before_action :signed_in_user # Retrieve current business flow before_action :set_business_flow, only: [:show, :edit, :update, :destroy] # Create the list of statuses to be used in the form before_action :set_statuses_list, only: [:new, :edit, :update, :create] # GET /business_flows # GET /business_flows.json def index @business_flows = BusinessFlow.order("hierarchy ASC") respond_to do |format| format.html # index.html.erb format.json { render json: @business_flows } end end # GET /business_flows/1 # GET /business_flows/1.json def show ### Retrieved by Callback function end # GET /business_flows/new # GET /business_flows/new.json def new @business_flow = BusinessFlow.new @business_flow.business_area_id = params[:business_area_id] end # GET /business_flows/1/edit def edit ### Retrieved by Callback function end # POST /business_flows # POST /business_flows.json def create @business_flow = BusinessFlow.new(business_flow_params) @business_flow.business_area_id = params[:business_area_id] @business_flow.updated_by = current_user.login @business_flow.created_by = current_user.login @business_flow.playground_id = current_user.current_playground_id @business_flow.owner_id = current_user.id respond_to do |format| if @business_flow.save format.html { redirect_to @business_flow, notice: 'Business flow was successfully created.' } format.json { render json: @business_flow, status: :created, location: @business_flow } else format.html { render action: "new" } format.json { render json: @business_flow.errors, status: :unprocessable_entity } end end end # PUT /business_flows/1 # PUT /business_flows/1.json def update ### Retrieved by Callback function @business_flow.updated_by = current_user.login respond_to do |format| if @business_flow.update_attributes(business_flow_params) format.html { redirect_to @business_flow, notice: 'Business flow was successfully updated.' } format.json { head :no_content } else format.html { render action: "edit" } format.json { render json: @business_flow.errors, status: :unprocessable_entity } end end end # DELETE /business_flows/1 # DELETE /business_flows/1.json def destroy ### Retrieved by Callback function @business_flow.destroy respond_to do |format| format.html { redirect_to business_flows_url } format.json { head :no_content } end end ### private functions private ### Use callbacks to share common setup or constraints between actions. # Retrieve current business flow def set_business_flow @business_flow = BusinessFlow.includes(:owner, :status).find(params[:id]) end ### before filters # Check for active session def signed_in_user redirect_to signin_url, notice: "You must log in to access this page." unless signed_in? end ### strong parameters def business_flow_params params.require(:business_flow).permit(:code, :name, :hierarchy, :status_id, :PCF_index, :PCF_reference, :description) end end 

单击“新建业务流”链接时记录

 --- !ruby/hash:ActionController::Parameters action: new controller: business_flows business_area_id: '2' 

validation业务流创建时记录

 --- !ruby/hash:ActionController::Parameters utf8: ✓ authenticity_token: PwhUukDm3f0OIDhOZfeKxwgtH7M5GFoOuy63Mt7Tcw= business_flow: !ruby/hash:ActionController::Parameters name: aaaaaaa code: bbbbbbb status_id: '8' description: '' hierarchy: cccccccc PCF_index: '' PCF_reference: '' commit: Create Business flow action: create controller: business_flows 

我可以想象在表单中隐藏了一个business_area_id字段,但是我希望有一个更聪明的方法让传递给new()函数的参数也可以在create()函数中使用,即使它们必须通过强参数。

作为初学者,我不能说我对问题的分析是否正确,我希望你能帮助我找到一个好的解决方案。

非常感谢你的帮助,

最好的祝福,

弗雷德

我看到你的新动作确实有business_area_id: '2'参数但是,在你的控制器的新动作中你没有实例化business_area。 它应该如下所示:

 class BusinessFlowsController < ApplicationController def new @business_area = BusinessArea.find params[:business_area_id] @business_flow = BusinessFlow.new # not needed here since this isn't being created yet # @business_flow.business_area_id = params[:business_area_id] end ... rest of code ... end 

现在您已实例化business_areaform_for应该能够正确构建应包含business_area_id的嵌套路径。 现在,您的business_flows控制器的创建操作应如下所示:

 def create @business_area = BusinessArea.find params[:business_area_id] @business_flow = @business_area.business_flows.build(business_flow_params) # assigning the parent id happens automatically in the build method # @business_flow.business_area_id = params[:business_area_id] @business_flow.updated_by = current_user.login @business_flow.created_by = current_user.login @business_flow.playground_id = current_user.current_playground_id @business_flow.owner_id = current_user.id ... rest of code ... end 

要确保表单的操作包括business_area_id请检查呈现的html。 表单的属性应如下所示:

action="/business_areas/<:business_area_id>/business_flows" method="post"

其中<:business_area_id>是父项的整数id,在您的情况下为2

你正在使用嵌套路线,所以这很好。 您没有发布您的视图代码,所以我假设您没有使用嵌套路由 POST到business_flows控制器的创建操作。 您的business_flow视图的表单应如下所示:

 # in your controller: @business_flow = BusinessFlow.new form_for [@business_area, @business_flow] do |f| ... rest of code ... 

这将使表单发布到business_flows控制器的嵌套创建操作。 这样父母的id将作为params[:business_area_id]进入路径。 然后,您可以像在创建操作中一样将该ID分配给您的子模型。