我正在尝试建模我的第一个rails 4项目,以实现从教程到现实世界的飞跃。
该应用程序是一个马秀注册。
我开始使用Cocoon和Formtastic做一些嵌套的Web表单: https://github.com/nathanvda/cocoon
购买我在将相关数据保存到表格时遇到问题。
当我保存我的条目时,rides表包含正确的值: test,entry_id,但不是horse_id
条目表没有ride_id值。它只有user_id(我手动设置在控制器中)
我的问题是:
我确信我缺少一些概念性概念,但我是否正确设置了模型关联?
如何编辑当前表单以正确保存数据?
当我在控制器中调试时,我得到的是一个奇怪的参数值:
{" utf8" =>"√"," authenticity_token" =>" xxxxxxxxxxxxxx =",&#34 ;条目" => {" show_date" =>" 10/26/2014"," rides_attributes" => {" 1407930343404& #34; => {"测试" =>"介绍B","马" => {"名称" => ;"普通马"," _destroy" =>""}}}},"提交" =>"创建条目","操作" =>"创建","控制器" =>"条目"}
我以为我会看到' horses_attributes'在' rides_attributes'哈希,但我只看到了马匹#39;
任何澄清,包括与示例的链接都将非常明确。
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :entries
has_many :rides, :through => :entries
has_many :horses, :through => :entries
has_many :riders, :through => :entries
end
class Entry < ActiveRecord::Base
belongs_to :user
has_many :rides, :dependent => :destroy
has_many :horses, :through => :rides
has_many :riders, :through => :rides
accepts_nested_attributes_for :rides, :allow_destroy => true
accepts_nested_attributes_for :horses
accepts_nested_attributes_for :riders
end
class Ride < ActiveRecord::Base
belongs_to :entry
belongs_to :user
has_one :horse #, :dependent => :destroy
has_one :rider
accepts_nested_attributes_for :horse
accepts_nested_attributes_for :rider
end
class Horse < ActiveRecord::Base
belongs_to :ride # :dependent => :destroy
belongs_to :user, :dependent => :destroy
end
class Rider < ActiveRecord::Base
#belongs_to :ride #, :dependent => :destroy
belongs_to :user, :dependent => :destroy
has_many :rides
end
这是我的部分架构:
create_table "entries", force: true do |t|
t.date "show_date"
t.integer "user_id"
t.integer "ride_id"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "entries", ["ride_id"], name: "index_entries_on_ride_id", using: :btree
add_index "entries", ["user_id"], name: "index_entries_on_user_id", using: :btree
create_table "horses", force: true do |t|
t.string "name"
t.string "horse_ncdcta"
t.string "owner_fname"
t.string "owner_lname"
t.date "coggins_date"
t.integer "ride_id"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "user_id"
end
add_index "horses", ["ride_id"], name: "index_horses_on_ride_id", using: :btree
create_table "riders", force: true do |t|
t.string "first_name"
t.string "last_name"
t.string "rider_ncdcta"
t.boolean "senior"
t.boolean "liability_signed"
t.integer "ride_id"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "riders", ["ride_id"], name: "index_riders_on_ride_id", using: :btree
create_table "rides", force: true do |t|
t.string "test"
t.integer "entry_id"
t.integer "rider_id"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "horse_id"
end
add_index "rides", ["entry_id"], name: "index_rides_on_entry_id", using: :btree
add_index "rides", ["rider_id"], name: "index_rides_on_rider_id", using: :btree
create_table "users", force: true do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at"
t.datetime "updated_at"
t.string "first_name"
t.string "last_name"
t.string "phone"
end
部分进入控制器:
def new
@user=current_user
@entry=Entry.new
end
def create
@entry = Entry.new(entry_params)
@entry.user_id=current_user[:id]
respond_to do |format|
if @entry.save
# example of params value
# {"utf8"=>"√", "authenticity_token"=>"xxxxxxxxxxxxxx=", "entry"=>{"show_date"=>"10/26/2014", "rides_attributes"=>{"1407930343404"=>{"test"=>"Intro B", "horses"=>{"name"=>"Plain Horse", "_destroy"=>""}}}}, "commit"=>"Create Entry", "action"=>"create", "controller"=>"entries"}
debugger
format.html { redirect_to @entry, notice: 'Entry was successfully created.' }
format.json { render :show, status: :created, location: @entry }
else
format.html { render :new }
format.json { render json: @entry.errors, status: :unprocessable_entity }
end
end
end
def entry_params
# added ids based on comments below
params.require(:entry).permit(:show_date, rides_attributes: [:id, :test, :_destroy, horses_attributes: [:name, :id]] )
end
的观点:
_form.html.haml
= semantic_form_for @entry do |f|
= f.inputs do
= f.label :show_date, "Show Date"
= f.input :show_date, :as => :select, :collection => [['08/03/2014', '08/03/2014'], ['09/14/2014', '09/14/2014'], ['10/26/2014', '10/26/2014'], ['11/15/2014', '11/15/2014']]
%h3 Rides
#rides
= f.semantic_fields_for :rides do |ride|
= render 'ride_fields', :f => ride
.links
= link_to_add_association 'add ride', f, :rides
= f.actions do
= f.action :submit
_ride_fields.html.haml
.nested-fields
= f.inputs do
= f.label :test, "Test"
= f.input :test, :as => :select, :collection => [['Intro A', 'Intro A'], ['Intro B', 'Intro B'], ['Intro C', 'Intro C']]
= f.semantic_fields_for :horses do |horse|
= render 'horse_fields', :f => horse
= link_to_add_association 'add horse', f, :horse
_horse_fields.html.haml
.nested-fields
=f.inputs do
= f.input :name
.links
= link_to_add_association 'add horse', f, :horse
答案 0 :(得分:0)
这就是我认为正在发生的事情,你是在Rides而不是Entry中嵌套。 Ride接受has_one马关系的嵌套属性,因此您可以看到“马”。如果你提交了针对Entry的马(它有has_many关系),你会看到horses_attributes。
在_form.html.haml的这一部分中,您已将ride
分配给f
= render 'ride_fields', :f => ride
然后在你的_ride_fields.html.haml中使用f
创建一个嵌套表单,该表单是从ride
变量(Ride has_one horse)创建的。
= f.semantic_fields_for :horses do |horse|
= render 'horse_fields', :f => horse
由于您的Ride
模型已accepts_nested_attributes_for :horse
,因此您在骑行中看到horses
。要查看horses_attributes
,您需要针对条目创建匹配马(它接受“马匹”的嵌套属性)。
我相信您可以通过更改此render
来修复此问题(在条目模型表单中传递):
= render 'ride_fields', :f => ride, :e => f
然后马嵌套这样的形式(从f
到e
):
= e.semantic_fields_for :horses do |horse|
= render 'horse_fields', :f => horse
答案 1 :(得分:0)
使用嵌套属性时,传递给form_for
的符号必须与关联名称匹配。你在做什么
f.semantic_fields_for :horses
但是游乐设施没有马匹协会,只有马协会。因为这个rails没有意识到你正在尝试使用嵌套属性,这就是为什么数据嵌套在键“horses”而不是“horses_attributes”之下。您当然需要更改允许的参数以匹配。
此外,如果骑行实际上只有一匹马,那么你不需要所有的东西来管理为骑行添加额外的马场。如果这是一个错误,那么请单独保留表单,但更改模型以便乘坐has_many :horses
和accepts_nested_attributes_for :horses
答案 2 :(得分:0)
我现在正确地使用下面的代码保存关系(有一个警告)。感谢以前的海报让我朝着正确的方向前进!
还有Formtastic文档链接:http://rdoc.info/github/justinfrench/formtastic/Formtastic/Inputs/SelectInput
警告:如果我不想添加新马(_ride_fields.html.haml),我无法弄清楚如何选择具有表单选择的现有马。添加新马工作正常
当我尝试使用当前注释的代码时,我得到错误:
骑行的未定义方法ride_id
我不确定这是一个形式问题,模型相关还是控制器。如果我不明白,我会将此作为一个单独的问题发布。
我在原帖中意识到,我不应该将外键(例如ride_id)保存到&#39;条目&#39; table因为它们被保存到entry_id字段中的相关表(rides)中。
条目控制器(部分):
class EntriesController < ApplicationController
before_filter :set_horses, :except => [:destroy, :index]
def new
@c_user=current_user[:id]
@user=current_user
@entry = current_user.entries.new
@horses = current_user.horses
end
def create
@entry = current_user.entries.new(entry_params)
respond_to do |format|
if @entry.save
format.html { redirect_to @entry, notice: 'Entry was successfully created.' }
format.json { render :show, status: :created, location: @entry }
else
format.html { render :new }
format.json { render json: @entry.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_horses
if current_user.admin?
@horses=Horse.all
else
@horses = current_user.horses
end
end
# Never trust parameters from the scary internet, only allow the white list through.
def entry_params
params.require(:entry).permit(:show_date, rides_attributes: [:id, :test, :_destroy, horse_attributes: [:name, :id]] )
end
end
entry.rb:
class Entry < ActiveRecord::Base
belongs_to :user
has_many :rides, :dependent => :destroy
has_many :horses, :through => :rides, :dependent => :destroy
has_many :riders, :through => :rides, :dependent => :destroy
accepts_nested_attributes_for :rides, :reject_if => lambda { |a| a[:test].blank? }, :allow_destroy => true
accepts_nested_attributes_for :horses, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => true
accepts_nested_attributes_for :riders, :allow_destroy => true
validates_presence_of :show_date
end
ride.rb:
class Ride < ActiveRecord::Base
belongs_to :entry, inverse_of: :entry
belongs_to :user, inverse_of: :user
has_one :horse
has_one :rider
accepts_nested_attributes_for :horse
end
horse.rb:
class Horse < ActiveRecord::Base
belongs_to :ride, :dependent => :destroy
belongs_to :user, :dependent => :destroy
end
_form.html.haml
= semantic_form_for @entry do |f|
= f.inputs do
= f.input :show_date, :as => :select, :collection => ['2014/08/03', '2014/09/14', '2014/10/26', '2014/11/15']
%h3 Rides
#rides
= f.semantic_fields_for :rides do |ride|
= render 'ride_fields', :f => ride
.links
= link_to_add_association 'add ride', f, :rides
= f.actions do
= f.action :submit
_ride_fields.html.haml
.nested-fields
= f.inputs do
= f.label :test, "Test"
= f.input :test, :as => :select, :collection => [['Intro A', 'Intro A'], ['Intro B', 'Intro B'], ['Intro C', 'Intro C']]
= if !@horses.empty?
-# both of next 2 lines give error: undefined method ride_id for <Ride:0x00000008cc3370>
-#= f.input :horse, :as => :select, :collection => @horses
-#= f.input :horse, :as => :select, :member_label => :name
= f.semantic_fields_for :horse do |horse|
= render 'horse_fields', :f => horse
.links
= link_to_add_association 'add new horse', f, :horse
_horse_fields.html.haml
.nested-fields
= f.inputs do
= f.input :name