NoMethodError Rails 4 App -> 嵌套属性问题

NoMethodError Rails 4 App -> Nested attribute issue

我正在开发一个 Rails 4 应用程序,我的模块之一是一般巡逻报告,其中用户根据他/她的轮班开始/停止创建报告。创建报告后,他们可以选择返回报告视图并添加巡逻报告。

在 gen_rep_ent 表单提交之前,一切都在进行中。

我得到的具体错误是:

 undefined method `general_report=' for #<GenRepEnt:0x007f871d9ea150>

其次是:

  def create              
    @general_report = GeneralReport.find(params[:general_report_id])
    @gen_rep_ent = GenRepEnt.new(gen_rep_ent_params)
    @gen_rep_ent.general_report = @gen_rep_ent <-- Problem Line

    respond_to do |format|
      if @gen_rep_ent.save
        format.html { redirect_to @general_report, notice: 'General Report Entry was successfully created.' }
        format.json { render :show, status: :created, location: @general_report}
      else
        format.html { render :new }
        format.json { render json: @general_report.errors, status: :unprocessable_entity }
      end
    end
  end

这是导致此处问题的第 3 行。

我的general_report模型有如下关系:

has_many :gen_rep_ents, dependent: :destroy

我的路线文件看起来像:

Rails.application.routes.draw do

  resources :mobile_alarm_reports

  resources :mobile_incident_reports

  resources :static_incident_reports

  resources :general_reports do 
    resources :gen_rep_ents, except: [:index], controller: 'general_reports/gen_rep_ents'
  end

  resources :visitor_parkings

  resources :residents

  resources :sites

  devise_for :users, controllers: { registrations: "registrations" }

  # Adds Static Pages 
  root 'home#index'

  get 'home/about'

  get 'home/contact'

  get 'home/pricing'

我的节目文件看起来像:

<% @gen_rep_ents.each do |gen_rep_ent| %>
  <table>
    <thead>
       <tr>
        <th>Time</th>
        <th>Report</th>
      </tr>     
    </thead>
    <tbody>
      <tr>
        <td><%= gen_rep_ent.time %></td>
        <td><%= gen_rep_ent.report %></td>
      </tr>
    </tbody>
    <% end %>
  </table>

gen_rep_ents_controller.rb: <-- 嵌套项

class GeneralReports::GenRepEntsController < ApplicationController
  before_action :set_gen_rep_ent, only: [:show, :edit, :update, :destroy]

  # GET /gen_rep_ents
  # GET /gen_rep_ents.json
  def index
    @gen_rep_ents = GenRepEnt.all
  end

  # GET /gen_rep_ents/1
  # GET /gen_rep_ents/1.json
  def show
  end

  # GET /gen_rep_ents/new
  def new
    @general_report = GeneralReport.find(params[:general_report_id])
    @gen_rep_ent = GenRepEnt.new
  end

  # GET /gen_rep_ents/1/edit
  def edit
  end

  # POST /gen_rep_ents
  # POST /gen_rep_ents.json
  def create
    @general_report = GeneralReport.find(params[:general_report_id])
    @gen_rep_ent = GenRepEnt.new(gen_rep_ent_params)
    @gen_rep_ent.general_report = @gen_rep_ent

    respond_to do |format|
      if @gen_rep_ent.save
        format.html { redirect_to @general_report, notice: 'General Report Entry was successfully created.' }
        format.json { render :show, status: :created, location: @general_report}
      else
        format.html { render :new }
        format.json { render json: @general_report.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /gen_rep_ents/1
  # PATCH/PUT /gen_rep_ents/1.json
  def update
    respond_to do |format|
      if @gen_rep_ent.update(gen_rep_ent_params)
        format.html { redirect_to @gen_rep_ent, notice: 'General Report Entry was successfully updated.' }
        format.json { render :show, status: :ok, location: @gen_rep_ent }
      else
        format.html { render :edit }
        format.json { render json: @gen_rep_ent.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /gen_rep_ents/1
  # DELETE /gen_rep_ents/1.json
  def destroy
    @gen_rep_ent.destroy
    respond_to do |format|
      format.html { redirect_to gen_rep_ents_url, notice: 'General Report Entry was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_gen_rep_ent
      @gen_rep_ent = GenRepEnt.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def gen_rep_ent_params
      params.require(:gen_rep_ent).permit(:time, :report, :general_report)
    end
end

general_reports_controller:<-- 父项

class GeneralReportsController < ApplicationController
  before_action :set_general_report, only: [:show, :edit, :update, :destroy]

  # GET /general_reports
  # GET /general_reports.json
  def index
    @general_reports = GeneralReport.all
  end

  # GET /general_reports/1
  # GET /general_reports/1.json
  def show
    @general_report = GeneralReport.find(params[:id])
    @gen_rep_ents = @general_report.gen_rep_ents
  end

  # GET /general_reports/new
  def new
    @general_report = GeneralReport.new
  end

  # GET /general_reports/1/edit
  def edit
  end

  # POST /general_reports
  # POST /general_reports.json
  def create
    @general_report = GeneralReport.new(general_report_params)

    respond_to do |format|
      if @general_report.save
        format.html { redirect_to @general_report, notice: 'General report was successfully created.' }
        format.json { render :show, status: :created, location: @general_report }
      else
        format.html { render :new }
        format.json { render json: @general_report.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /general_reports/1
  # PATCH/PUT /general_reports/1.json
  def update
    respond_to do |format|
      if @general_report.update(general_report_params)
        format.html { redirect_to @general_report, notice: 'General report was successfully updated.' }
        format.json { render :show, status: :ok, location: @general_report }
      else
        format.html { render :edit }
        format.json { render json: @general_report.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /general_reports/1
  # DELETE /general_reports/1.json
  def destroy
    @general_report.destroy
    respond_to do |format|
      format.html { redirect_to general_reports_url, notice: 'General report was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_general_report
      @general_report = GeneralReport.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def general_report_params
      params.require(:general_report).permit(:user_id, :site_id, :date, :shift_start, :shift_end, :gp_number)
    end
end

我不太确定哪里出了问题,因为我已经一遍又一遍地查看了教程,它与我所看到的完全匹配。

编辑#1

我的 GenRepEnt 模型看起来像:

class GenRepEnt < ActiveRecord::Base

  belongs_to :general_report

end

编辑 # 2

执行迁移并将 belongs_to :general_report 添加到模型后,出现以下错误:

ActiveRecord::AssociationTypeMismatch in GeneralReports::GenRepEntsController#create

看起来您正在尝试在 GenRepEnt class 的实例上设置 general_report,但该方法不存在。这可能是因为未在 GenRepEnt 模型中建立关联。

在模型 gen_rep_ent.rb 中添加以下关联:

belongs_to :general_report

声明此关联后 Rails 将在 GenRepEnt 的每个实例上定义一些方法,包括:

general_report
general_report=

您还需要生成一个迁移,将新列 general_report_id 添加到 gen_rep_ents table.

在您的终端中 运行 rails g migration AddGeneralReportRefToGenRepEnts general_report:references

这应该生成如下所示的迁移:

class AddGeneralReportRefToGenRepEnts < ActiveRecord::Migration
  def change
    add_reference :gen_rep_ents, :general_report, index: true, foreign_key: true
  end
end

接下来,运行 使用 rake db:migrate 进行迁移并重新启动您的应用。

阅读有关 belongs_to 协会的更多信息 here