【问题标题】:Rails: model accepts nested attributes but controller doesn't seem to careRails:模型接受嵌套属性,但控制器似乎并不关心
【发布时间】:2023-03-11 15:05:01
【问题描述】:

我正在努力降低嵌套属性。在Railscast 196 工作后,我尝试设置自己的应用程序来进行基本嵌套。用户可以创建寻宝游戏。每次狩猎都包含一系列任务(可以属于任何狩猎,而不仅仅是一个)。我得到了一点帮助 here 并试图从 similar issue 的帖子中学习,但我仍然卡住了。我已经折腾了好几个小时了,我撞到了一堵砖墙。

class HuntsController < ApplicationController

  def index
     @title = "All Hunts"
     @hunts = Hunt.paginate(:page => params[:page])
  end

  def show
    @hunt = Hunt.find(params[:id])
    @title = @hunt.name 
    @tasks = @hunst.tasks.paginate(:page => params[:page])
  end

  def new
    if current_user?(nil) then    
      redirect_to signin_path
    else
      @hunt = Hunt.new
      @title = "New Hunt"
      3.times do
        #hunt =  @hunt.tasks.build 
        #hunt = @hunt.hunt_tasks.build  
        hunt = @hunt.hunt_tasks.build.build_task
      end
    end
  end

  def create
    @hunt = Hunt.new(params[:hunt])
    if @hunt.save
      flash[:success] = "Hunt created!"
      redirect_to hunts_path
    else
      @title = "New Hunt"
      render 'new'     
    end
  end
....
 end

使用这段代码,当我尝试创建一个新的狩猎时,我被告知没有方法“build_task”(它是未定义的)。因此,当我删除该行并使用上面注释掉的第二段代码时,我得到了下面的错误。

    NoMethodError in Hunts#new

    Showing /Users/bendowney/Sites/MyChi/app/views/shared/_error_messages.html.erb where line #1 raised:

    You have a nil object when you didn't expect it!
    You might have expected an instance of ActiveRecord::Base.
    The error occurred while evaluating nil.errors
    Extracted source (around line #1):

    1: <% if object.errors.any? %>
    2:   <div id="error_explanation">
    3:     <h2><%= pluralize(object.errors.count, "error") %> 
    4:         prohibited this <%= object.class.to_s.underscore.humanize.downcase %> 

    Trace of template inclusion: app/views/tasks/_fields.html.erb, app/views/hunts/_fields.html.erb, app/views/hunts/new.html.erb

当我使用在搜寻控制器中注释掉的第一段代码时,我收到一条错误消息,告诉我我的“新”方法有一个未初始化的常量:

    NameError in HuntsController#new
uninitialized constant Hunt::Tasks

我已经束手无策了。关于我到底做错了什么有什么建议吗?或策略这是我的模型:

    class Hunt < ActiveRecord::Base
      has_many :hunt_tasks
      has_many :tasks, :through => :hunt_tasks #, :foreign_key => :hunt_id

      attr_accessible :name
      validates :name,  :presence => true,
                        :length   => { :maximum => 50 } ,
                        :uniqueness => { :case_sensitive => false }
    end

    class Task < ActiveRecord::Base

      has_many :hunt_tasks
      has_many :hunts, :through => :hunt_tasks#, :foreign_key => :hunt_id

      attr_accessible :name 
      validates :name,  :presence => true,
                        :length   => { :maximum => 50 } ,
                        :uniqueness => { :case_sensitive => false }

    end

    class HuntTask < ActiveRecord::Base
      belongs_to :hunts # the id for the association is in this table
      belongs_to :tasks
    end

【问题讨论】:

  • 嵌套属性有一种方式让你陷入困境,在走这条路之前探索使用表单类的选项(请参阅blog.codeclimate.com/blog/2012/10/17/… 中的第 3 点,了解一种可能的方法)跨度>

标签: ruby-on-rails rails-activerecord


【解决方案1】:

当您在 2 个模型之间创建关联时,您可以向它们添加功能,具体取决于您定义关系的方式。每种类型都会为您的模型添加不同的功能。

我真的推荐阅读本指南 -> http://guides.rubyonrails.org/association_basics.html

您可以在此处查看每种不同类型的关联添加了哪些功能。 http://guides.rubyonrails.org/association_basics.html#detailed-association-reference

如果我做一个像...这样的小示例程序

class HuntsController < ApplicationController
  # GET /hunts
  # GET /hunts.json
  def index
    @hunts = Hunt.all

    respond_to do |format|
      format.html # index.html.erb
      format.json { render json: @hunts }
    end
  end

  # GET /hunts/1
  # GET /hunts/1.json
  def show
    @hunt = Hunt.find(params[:id])

    respond_to do |format|
      format.html # show.html.erb
      format.json { render json: @hunt }
    end
  end

  # GET /hunts/new
  # GET /hunts/new.json
  def new
    @hunt = Hunt.new
    3.times do |i|
        t = @hunt.hunt_tasks.build
        t.name = "task-#{i}"
    end

    respond_to do |format|
      format.html # new.html.erb
      format.json { render json: @hunt }
    end
  end

  # GET /hunts/1/edit
  def edit
    @hunt = Hunt.find(params[:id])
  end

  # POST /hunts
  # POST /hunts.json
  def create
    @hunt = Hunt.new(params[:hunt])

    respond_to do |format|
      if @hunt.save
        format.html { redirect_to @hunt, notice: 'Hunt was successfully created.' }
        format.json { render json: @hunt, status: :created, location: @hunt }
      else
        format.html { render action: "new" }
        format.json { render json: @hunt.errors, status: :unprocessable_entity }
      end
    end
  end

  # PUT /hunts/1
  # PUT /hunts/1.json
  def update
    @hunt = Hunt.find(params[:id])

    respond_to do |format|
      if @hunt.update_attributes(params[:hunt])
        format.html { redirect_to @hunt, notice: 'Hunt was successfully updated.' }
        format.json { head :no_content }
      else
        format.html { render action: "edit" }
        format.json { render json: @hunt.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /hunts/1
  # DELETE /hunts/1.json
  def destroy
    @hunt = Hunt.find(params[:id])
    @hunt.destroy

    respond_to do |format|
      format.html { redirect_to hunts_url }
      format.json { head :no_content }
    end
  end
end

还有这个模型关系

class Hunt < ActiveRecord::Base
    has_many :hunt_tasks
end

class HuntTask < ActiveRecord::Base
  belongs_to :hunt
end

并在views/hunts/_form.html中的某处添加这个sn-p

<% @hunt.hunt_tasks.each do |t| %>
    <li><%= t.name %></li>
<% end %>

看到创建了 3 个任务,我得到了常规输出。

【讨论】:

  • 老兄,你太棒了。谢谢!
【解决方案2】:

你试过了吗 hunttask = @hunt.build_hunt_task 在 HuntsController 的新动作中?

http://guides.rubyonrails.org/association_basics.html#detailed-association-reference

【讨论】:

  • 我试了一下,但又遇到了一个无方法错误。 NoMethodError in HuntsController#new undefined method build_hunt_task' for []:ActiveRecord::Relation`
  • 对不起,我建议使用 has_one 关系附带的构建器方法...您要在此处使用的是 has_many 关联,它根据文档 -> guides.rubyonrails.org/… 提供 @987654325 @ 方法。您已经尝试使用但已注释掉。你这样做的原因是什么?
  • 我评论 @hunt.hunt_tasks.build 的原因是它返回了您在上一条评论中提到的错误消息。我不确定您在最后一条评论中的确切含义。你能澄清一下吗?
【解决方案3】:

您看到的即时错误位于 app/views/shared/_error_messages.html.erb 中。对象未定义,您可能需要找到调用该部分的位置。查找:

render :partial=>"/shared/error"

替换为

render :partial=>"/shared/error", :locals=>{:object=>@hunt}

如果你在 app/views/hunts 某处找到它,如果你在 app/views/tasks 中找到它,请将 @hunt 替换为 @task

这至少会告诉你真正的错误是什么。

【讨论】:

  • 当我将搜索视图中的 new.html.erb 更改为 &lt;%= render 'shared/error_messages', :locals=&gt;{:object=&gt;@hunt} %&gt; 时,我仍然会遇到与以前相同的错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-15
  • 2021-01-28
  • 1970-01-01
相关资源
最近更新 更多