嵌套模型窗体中的 NoMethodError



该项目是一个简单的锻炼创建器,您可以在其中将锻炼添加到锻炼计划中。

我一直在遵循涵盖嵌套模型表单的 Railscast 以允许动态添加和删除练习,但遇到了错误,需要作为新开发人员的第二意见。

我不断收到的错误是:计划中没有方法错误#显示

这是提取的代码,带星号的行突出显示错误:

<fieldset>
  **<%= link_to_add_fields "Add Exercise", f, :exercise %>**
  <%= f.text_field :name %>
  <%= f.number_field :weight %>
  <%= f.number_field :reps %>

注意:我已创建锻炼模型,但没有创建锻炼控制器。锻炼只能存在于计划中,但我不确定我是否仍然需要在锻炼控制器中创建一个操作才能添加练习?

我几乎逐字逐句地遵循了 Railscast(我略微偏离了_exercise_fields部分(,因此您可以根据他在笔记中共享的文件查看我的文件。

我的架构.rb

create_table "exercises", force: true do |t|
  t.string   "name"
  t.integer  "weight"
  t.integer  "reps"
  t.datetime "created_at"
  t.datetime "updated_at"
  t.integer  "plan_id"
end
create_table "plans", force: true do |t|
  t.string   "title"
  t.datetime "created_at"
  t.datetime "updated_at"
end

我的计划模型:

class Plan < ActiveRecord::Base
has_many :exercises
accepts_nested_attributes_for :exercises, allow_destroy: true
end

我的锻炼模型:

class Exercise < ActiveRecord::Base
belongs_to :plan
end

我的_form.html.erb

<%= form_for @plan do |f| %>
  <% if @plan.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@plan.errors.count, "error") %> prohibited this plan from being saved:</h2>
      <ul>
      <% @plan.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>
  <div class="field">
    <%= f.label :title %><br>
    <%= f.text_field :title %>
  </div>
  <%= f.fields_for :exercises do |builder| %>
    <%= render 'exercise_fields', f: builder %>
  <% end %>
  <%= link_to_add_fields "Add Exercise", f, :exercises %>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

我的_exercise_fields.html.erb

<fieldset>
  <%= link_to_add_fields "Add Exercise", f, :exercise %>
  <%= f.text_field :name %>
  <%= f.number_field :weight %>
  <%= f.number_field :reps %>
  <%= f.hidden_field :_destroy %>
  <%= link_to "remove", '#', class: "remove_fields" %>
</fieldset>

我的计划.js.咖啡

jQuery ->
  $('form').on 'click', '.remove_fields', (event) ->
    $(this).prev('input[type=hidden]').val('1')
    $(this).closest('fieldset').hide()
    event.preventDefault()
  $('form').on 'click', '.add_fields', (event) ->
    time = new Date().getTime()
    regexp = new RegExp($(this).data('id'), 'g')
    $(this).before($(this).data('fields').replace(regexp, time))
event.preventDefault()

我的application_helper.rb

module ApplicationHelper
  def link_to_add_fields(name, f, association)
    new_object = f.object.send(association).klass.new
    id = new_object.object_id
    fields = f.fields_for(association, new_object, child_index: id) do |builder|
      render(association.to_s.singularize + "_fields", f: builder)
    end
    link_to(name, '#', class: "add_fields", data: {id: id, fields: fields.gsub("n", "")})
  end
end

我对编程比较陌生,所以如果我很容易忽略某些东西,我提前道歉。非常感谢任何帮助、建议或线索,以便来源阅读我的问题。

谢谢!

实现您寻求的功能后,我将给出一些想法:


接受嵌套属性

如您所知,您可以使用 accepts_nested_attributes_for 函数将属性从父模型传递到嵌套模型

虽然相对简单,但它有一个学习曲线。所以我将在这里解释如何使用它:

#app/models/plan.rb
Class Plan < ActiveRecord::Base
    has_many :exercises
    accepts_nested_attributes_for :exercises, allow_destroy: true
end

这为plan模型提供了"命令",以发送任何额外的数据(如果正确呈现(

要正确发送数据(在 Rails 4 中(,有几个重要步骤:

1. Build the ActiveRecord Object
2. Use `f.fields_for` To Display The Nested Fields
3. Handle The Data With Strong Params

生成活动记录对象

#app/controllers/plans_controller.rb
def new
    @plan = Plan.new
    @plan.exericses.build
end

使用 f.fields_for 显示嵌套字段

#app/views/plans/new.html.erb
<%= form_for @plans do |f| %>
    <%= f.fields_for :exercises do |builder| %>
        <%= builder.text_field :example_field %>
    <% end %>
<% end %>

使用强参数处理数据

#app/controllers/plans_controller.rb
def create
    @plan = Plan.new(plans_params)
    @plan.save
end
private
def plans_params
    params.require(:plan).permit(:fields, exerices_attributes: [:extra_fields])
end

这应该将所需的数据传递到嵌套模型。没有这个,您将无法传递数据,并且您的嵌套表单将根本不起作用


附加额外字段

附加额外的字段是棘手的部分

问题是,只能在form对象(仅存在于实例中(中动态生成新的f.fields_for对象

Ryan Bates 通过将当前form对象发送给帮助程序来解决此问题,但这会导致问题,因为帮助程序随后将新字段的整个源代码附加到链接的on click事件中(效率低下(


我们发现本教程更合适

它的工作原理是这样的:

  1. 创建 2 个部分:f.fields_forform 部分(对于 ajax(
  2. 创建新路由(ajax 终结点(
  3. 创建新的控制器操作(以添加额外字段(
  4. 创建 JS 以添加额外字段

创建 2 个部件

#app/views/plans/add_exercise.html.erb
<%= form_for @plan, :url => plans_path, :authenticity_token => false do |f| %>
        <%= render :partial => "plans/exercises_fields", locals: {f: f, child_index: Time.now.to_i} %>
<% end %>

#app/views/plans/_exercise_fields.html.erb
<%= f.fields_for :exercises, :child_index => child_index do |builder| %>
     <%= builder.text_field :example %>
<% end %>

创建新路由

   #config/routes.rb
   resources :plans do
       collection do
           get :add_exercise
       end
   end

创建控制器操作

#app/controllers/plans_controller.rb
def add_exercise
     @plan = Plan.new
     @plan.exercises.build
     render "add_exericse", :layout => false
end

创建 JS 以添加额外字段

#app/assets/javascripts/plans.js.coffee
$ ->
   $(document).on "click", "#add_exercise", (e) ->
       e.preventDefault();
          #Ajax
          $.ajax
            url: '/messages/add_exercise'
            success: (data) ->
                 el_to_add = $(data).html()
                 $('#exercises').append(el_to_add)
            error: (data) ->
                 alert "Sorry, There Was An Error!"

为庞大的帖子道歉,但它应该有效并帮助您显示更多信息

相关内容

  • 没有找到相关文章

最新更新