javascript - 使用连接表元数据创建 Rails 4 表单

标签 javascript ruby-on-rails ruby forms ruby-on-rails-4

这里是非常新的 Rails 4 开发人员。我有一个用户正在创建练习的表单。练习可以有很多设备,设备可以是可选的(认为俯卧撑代表做俯卧撑)。我将这个“可选”字段存储在连接表 exercise_equipment 中。

我无法获取参数以通过我选择的集合元素的值实际发送。请参阅下面的模型、 View 、 Controller 和参数。

以下是我的模型的属性/关系:

# id        :integer
# name      :string
# is_public :boolean
Exercise
    has_many :exercise_equipment
    has_many :equipment, :through => :exercise_equipment
    accepts_nested_attributes_for :exercise_equipment


# id           :integer
# exercise_id  :integer
# equipment_id :integer
# optional     :boolean
ExerciseEquipment
    belongs_to :exercise
    belongs_to :equipment
    accepts_nested_attributes_for :equipment


# id   :integer
# name :string
Equipment
    has_many :exercise_equipment
    has_many :exercises, :through => :exercise_equipment

这里有一些(可能)相关的 Controller 方法:

def new
  @exercise = Exercise.new
  @exercise.exercise_equipment.build
end

def create
  @exercise = Exercise.new( exercise_params )
  if @exercise.save
    redirect_to @exercises
  else
    render 'new'
  end
end

def edit
  @exercise = Exercise.find( params[:id] )
end

def update
  @exercise = Exercise.find( params[:id] )
  if @exercise.update_attributes( exercise_params )
    redirect_to @exercises
  else
    render 'edit'
  end
end

def exercise_params
  params.require( :exercise ).permit(
    :name,
    :is_public,
    exercise_equipment_attributes: [
      :id,
      :optional,
      equipment_attributes: [
        :id,
        :name
      ],
    ]
  )
end

这是我创建一个 View 来做我想做的事情的镜头:

练习/new.html.erb

<%= form_for @exercise do |f| %>
  <%= render 'form', f: f %>
  <%= f.submit "New Exercise" %>
<% end %>

练习/_form.html.erb

<%= f.label :name %><br />
<%= f.text_field :name %>

<%= f.check_box :is_public %> Public

<%= f.fields_for( :exercise_equipment ) do |eef|
  <%= eef.fields_for( :equipment ) do |ef|
    ef.collection_select :id, Equipment.all, :id, :name %>
  <% end %>
  <%= eef.check_box :is_optional %> Optional
<% end %>

当我将所有这些放在一起并提交对现有练习的更新时,所有值都经过 params 哈希,但没有更改为我选择的新值...

Parameters: {
  "utf8"=>"[checkbox]",
  "authenticity_token"=>"[token]",
  "exercise"=>{
    "name"=>"Test", 
    "is_public"=>"1", 
    "exercise_equipment_attributes"=>{
      "0"=>{
        "equipment_attributes"=>{
          "id"=>"1"
        }, 
        "optional"=>"1", 
        "id"=>"2" 
      } 
    } 
  },
  "commit"=>"Save Exercise",
  "id"=>"1" 
}

如果您能帮助我,我将不胜感激。如果您需要更多信息,请告诉我,我可以提供。

编辑

这是更新前数据库的状态:

postgres@=>db=# select id, name, is_public from exercises;
 id | name | is_public 
----+------+-----------
  2 | Test | t
(1 row)

Time: 61.279 ms
postgres@=>db=# select id, exercise_id, equipment_id, optional from exercise_equipment;
 id | exercise_id | equipment_id | optional 
----+-------------+--------------+----------
  2 |           2 |            1 | t
(1 row)

Time: 58.819 ms
postgres@=>db=# select id, name from equipment where id = 1;
 id |    name     
----+-------------
  1 | Freeweights
(1 row)

然后我转到该练习的更新路线,从收藏中选择不同的设备,然后提交表格。我得到以下 Rails 控制台结果:

Started PATCH "/exercises/system-test" for 127.0.0.1 at 2014-08-12 23:48:18 -0400
Processing by ExercisesController#update as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"PsbbUPSCiIew2Fd22Swn+K4PmLjwNDCrDdwXf9YBcm8=", "exercise"=>{"name"=>"Test", "is_public"=>"1", "exercise_equipment_attributes"=>{"0"=>{"equipment_attributes"=>{"id"=>"1"}, "optional"=>"1", "id"=>"2"}}}, "commit"=>"Save Exercise", "id"=>"system-test"}
  Exercise Load (60.5ms)  SELECT  "exercises".* FROM "exercises"  WHERE "exercises"."slug" = 'system-test'  ORDER BY "exercises"."id" ASC LIMIT 1
   (57.3ms)  BEGIN
  ExerciseEquipment Load (76.2ms)  SELECT "exercise_equipment".* FROM "exercise_equipment"  WHERE "exercise_equipment"."exercise_id" = $1 AND "exercise_equipment"."id" IN (2)  [["exercise_id", 2]]
  Equipment Load (59.1ms)  SELECT  "equipment".* FROM "equipment"  WHERE "equipment"."id" = $1 LIMIT 1  [["id", 1]]
  User Load (60.3ms)  SELECT  "users".* FROM "users"  WHERE "users"."id" = $1 LIMIT 1  [["id", 10]]
  Exercise Exists (60.5ms)  SELECT  1 AS one FROM "exercises"  WHERE ("exercises"."name" = 'Test' AND "exercises"."id" != 2 AND "exercises"."user_id" = 10) LIMIT 1
   (64.8ms)  COMMIT
Redirected to http://localhost:3000/exercises/system-test
Completed 302 Found in 590ms (ActiveRecord: 580.0ms)


Started GET "/exercises/system-test" for 127.0.0.1 at 2014-08-12 23:48:19 -0400
Processing by ExercisesController#show as HTML
  Parameters: {"id"=>"system-test"}
  Exercise Load (64.1ms)  SELECT  "exercises".* FROM "exercises"  WHERE "exercises"."slug" = 'system-test'  ORDER BY "exercises"."id" ASC LIMIT 1
  Equipment Load (58.7ms)  SELECT "equipment".* FROM "equipment" INNER JOIN "exercise_equipment" ON "equipment"."id" = "exercise_equipment"."equipment_id" WHERE "exercise_equipment"."exercise_id" = $1  [["exercise_id", 2]]
  Rendered exercises/show.html.erb within layouts/application (122.7ms)
  User Load (60.1ms)  SELECT  "users".* FROM "users"  WHERE "users"."id" = 10  ORDER BY "users"."id" ASC LIMIT 1
  Rendered shared/_header.html.erb (61.9ms)
  Rendered shared/_alerts.html.erb (0.1ms)
Completed 200 OK in 264ms (Views: 21.3ms | ActiveRecord: 240.8ms)

最佳答案

首先,您需要确保正确定义关联。

任何 has_many 关联都应该用复数名称定义 -

#app/models/exercise.rb
Class Exercise < ActiveRecord::Base
    has_many :exercise_equipments
    has_many :equipments, :through => :exercise_equipments

    accepts_nested_attributes_for :exercise_equipments
end

#app/models/exercise_equipment.rb
Class ExerciseEquipment < ActiveRecord::Base
   belongs_to :exercise
   belongs_to :equipment
end

#app/models/equipment.rb
Class Equipment < ActiveRecord::Base
   has_many :exercise_equipments
   has_many :exercises, through: :exercise_equipments
end

如果您已经开始使用它,并且对您所拥有的感到满意,那么我建议您保留当前的设置。但是,您可能希望对 convention's 采用以上内容清酒

编辑 我从删除的答案中看到 Beartech 对此进行了调查,结果证明 Rails 将 Equipment/Equipments 视为相同。值得忽略以上内容,但我将其留作将来引用


参数

I cannot get the parameters to actually send through the values of the collection element that I pick. See below for the model, view, controller, and parameters.

我想我明白你的意思 - 你正在寻找更新记录,但它不会将更新的参数发送到你的 Controller ,因此阻止它被更新。

虽然我看不到任何明显的问题,但我建议问题在于您正在尝试填充 Exercise 对象的 exercise_id。您需要为 exercise_equipment 对象定义它:

<%= f.fields_for :exercise_equipment do |eef| %>
   <%= eef.collection_select :equipment_id, Equipment.all, :id, :name %>
   <%= eef.check_box :is_optional %>
<% end %>

这将按照此处所述填充您的exercise_equipment 表:

Time: 61.279 ms
postgres@=>db=# select id, exercise_id, equipment_id, optional from exercise_equipment;
 id | exercise_id | equipment_id | optional 
----+-------------+--------------+----------
  2 |           2 |            1 | t
(1 row)

目前,您正在使用 equipment_id 填充 Equipment 模型 - 这是行不通的。以这种方式填充模型将服务器创建新记录,而不是更新已创建的记录


额外字段

I want to have a link to add an additional equipment field when it is clicked, similar to how Ryan Bates did it in this RailsCast, but the helper method he writes( see "Show Notes" tab if you're not subscribed to see the source ) seems to become substantially more complex when dealing with the nested views shown in my code below. Any help in dealing with this?

这是一座需要克服的棘手山峰

Ryan 在这个过程中使用了相当过时的方法(预填充链接,然后让 JS 追加字段)。 “正确”的方法是构建一个新对象并附加来自 ajax 的 fields_for。听起来很难?那是因为它是:)

操作方法如下:

#config/routes.rb
resources :exercises do
   collection do
       get :ajax_update #-> domain.com/exercises/ajax_update
   end
end

#app/models/exercise.rb
Class Exercise < ActiveRecord::Base
   def self.build
       exercise = self.new
       exercise.exercise_equipment.build
   end
end

#app/controllers/exercises_controller.rb
Class ExercisesController < ApplicationController
   def new
       @exercise = Exercise.build
   end

   def ajax_update
      @exercise = Exercise.build
      render "add_exercise", layout: false #> renders form with fields_for
   end
end

#app/views/exercises/add_exercise.html.erb
<%= form_for @exercise do |f| %>
   <%= render partial: "fields_for", locals: { form: f } %>
<% end %>

#app/views/exercises/_fields_for.html.erb
<%= f.fields_for :exercise_equipment, child_index: Time.now.to_i do |eef| %>
    <%= eef.collection_select :equipment_id, Equipment.all, :id, :name  %>
    <%= eef.check_box :is_optional %>
<% end %>

#app/views/exercises/edit.html.erb
<%= form_for @exercise do |f| %>
    <%= render partial: "fields_for", locals: { form: f } %>
    <%= link_to "Add Field", "#", id: "add_field" %>
<% end %>

#app/assets/javascripts/application.js
$(document).on("click", "#add_field", function() {
    $.ajax({
       url: "exercises/ajax_update",
       success: function(data) {
          el_to_add = $(data).html()
          $('#your_id').append(el_to_add)
       }
    });
 });

关于javascript - 使用连接表元数据创建 Rails 4 表单,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25277496/

相关文章:

ruby-on-rails - 将 Rails 应用程序从 Windows 移植到 Mac 或 Linux

ruby-on-rails - 在 Parent 的节目中创建新的 Child

javascript - Ruby on rails3 javascript 代码放在哪里

ruby-on-rails - 范围不与其他范围冲突

javascript - 我想更新 mongodb 中包含日期时间字段的对象数组

javascript - 在 Angular 中使用外部库

JavaScript 等同于 Guava 的先决条件?

javascript - 滚动时自动显示隐藏的 div

html - rails -nokogiri GEM : Detect MIME type of image in URL

ruby-on-rails - 如何计算此 postgres JOIN GROUP BY 的行数(在 Rails 范围内)