多态关联事务在 Rails 5 中失败
Polymorphic Associaton transaction fails in Rails 5
我无法让我的关联保存在 localhost:3000/controller_name/new
中。我相信这是由于 belongs_to
failing validation, but I am not sure how to fix it (beyond just dropping the association via requires:false
/optional: true
, the consequences of which I am not sure of). I created my association following this tutorial 但它是针对 rails.
的先前版本
我有一个多态地址 table 可以属于事件、企业、用户等。我正在尝试将它添加到事件中。
地址迁移 - 您可以看到它引用 addressable
:
class CreateAddresses < ActiveRecord::Migration[5.1]
def change
create_table :addresses do |t|
t.string :address
t.decimal :latitude, null: false, precision: 10, scale: 6, index: true
t.decimal :longitude, null: false, precision: 10, scale: 6, index: true
t.references :addressable, polymorphic: true, index: true
end
end
end
地址模型:
class Address < ApplicationRecord
belongs_to :addressable, polymorphic: true
end
事件模型:
class Event < ApplicationRecord
has_one :address, as: :addressable
accepts_nested_attributes_for :address
end
事件控制器:
class EventsController < ApplicationController
#...stuff...
# GET /events/new
def new
@event = Event.new
@event.address = @event.build_address
#@event.address = Address.new(addressable: @event)
#@event.address = @event.create_address
#@event.address = @addressable.User.new
end
#...stuff...
你可以看到我尝试了多种方法来创建事件的地址,它们主要创建以下项目,使用 addressable
的方法会导致 Nil
崩溃。
#<Address id: nil, address: nil, latitude: nil, longitude: nil, addressable_type: "Event", addressable_id: nil>
事件表(使用 Simple_form gem):
<%= simple_form_for @event do |f| %>
<%= f.input :name %>
<%= f.input :description %>
<%= f.simple_fields_for :address do |address| %>
<%= render :partial => 'shared/address/form', :locals => {:f => address} %>
<% end %>
<%= f.button :submit %>
<% end %>
部分地址形式:
<!-- Google Maps Must be loaded -->
<% content_for :head do %>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCMh8-5D3mJSXspmJrhSTtt0ToGiA-JLBc&libraries=places"></script>
<% end %>
<div id="map"></div>
<%= f.input :address %>
<%= f.input :latitude %>
<%= f.input :longitude %>
表单呈现良好。当我尝试保存时,我得到
Started POST "/events" for 127.0.0.1 at 2017-07-01 16:06:23 -0400
Processing by EventsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"R0zlSs3UUNV3x8sQn5ocmE4jP12uOsFza7FezBAuhP4sw2MhF1OhixF8sAfDsLpfMEX7x5rhJ9HZfbKna8ncEA==", "event"=>{"name"=>"asd", "description"
=>"asd", "address_attributes"=>{"address"=>"asd", "latitude"=>"1", "longitude"=>"1"}}, "commit"=>"Create Event"}
(0.1ms) begin transaction
(0.1ms) rollback transaction
我一直在 new
页面上。如果我将 byebug
插入 create
并打印出 @event.errors
它会显示:
#<ActiveModel::Errors:0x007fb29c34a9a8 @base=#<Event id: nil, name: "asd", description: "asd", min_users: nil, max_users: nil, start_time: nil, recurring: nil, created_at: nil, upd
ated_at: nil>, @messages={:"address.addressable"=>["must exist"]}, @details={:"address.addressable"=>[{:error=>:blank}]}>
如何创建 address.addressable?如某些 SO 答案所建议的那样关闭需要验证的后果是什么?
运行 rake db:schema:dump,然后检查 db/schema.rb 中的文件,确保你有如下 2 个字段
* t.integer :addressable_id,
* t.string :addressable_type
有关更多详细信息,请参阅 link 关于 Activerecord Polymorphic Associations,如果您的架构有问题,则可以 运行 迁移如下
t.references :addressable, polymorphic: true, index: true
由于事件通过多态关联有多个地址,您可以使用this link创建地址
下面是示例代码
@address = @event.addresses.build(attributes = {}, ...)
您可以使用@address 而不是@event.address
发现了问题并写了一篇 blog post 对此进行了深入讨论。基本上我遇到了 2 个不同的问题
1.The 我收到错误 - "address.addressable"=>["must exist"]
。 address.addressable 是 'parent' table 的元组 ID。在我的例子中,它是事件 ID。这个错误试图告诉我,当我们试图将它保存在控制器的创建函数中时,新地址中缺少这个外键。就像我在问题中所说的那样,您可以设置 optional:true
来忽略这个问题,并且在保存事件后它会以某种方式神奇地被填充。或者你可以在保存之前在创建函数中手动分配它。
def create
@event = Event.new(event_params)
@event.address.addressable = @event #<<<<<<<<<<< manually assign address.addressable
respond_to do |format|
if @event.save #Saves the event. Addressable has something to reference now, but validation does not know this in time
format.html { redirect_to @event, notice: 'Event was successfully created.' }
format.json { render :show, status: :created, location: @event }
else
#dont forget to remove the 'byebug' that was here
format.html { render :new }
format.json { render json: @event.errors, status: :unprocessable_entity }
end
end
end
2.Event ID 是一个字符串。在我的地址迁移中,我使用的是 t.references :addressable, polymorphic: true, index: true
和 addressable_id
整数类型的别名。我需要更改我的迁移以使用字符串 ID - 所以删除 references
行并添加它。
t.string :addressable_id, index: true
t.string :addressable_type, index: true
博客 post.
对此进行了更详细的介绍
我无法让我的关联保存在 localhost:3000/controller_name/new
中。我相信这是由于 belongs_to
failing validation, but I am not sure how to fix it (beyond just dropping the association via requires:false
/optional: true
, the consequences of which I am not sure of). I created my association following this tutorial 但它是针对 rails.
我有一个多态地址 table 可以属于事件、企业、用户等。我正在尝试将它添加到事件中。
地址迁移 - 您可以看到它引用 addressable
:
class CreateAddresses < ActiveRecord::Migration[5.1]
def change
create_table :addresses do |t|
t.string :address
t.decimal :latitude, null: false, precision: 10, scale: 6, index: true
t.decimal :longitude, null: false, precision: 10, scale: 6, index: true
t.references :addressable, polymorphic: true, index: true
end
end
end
地址模型:
class Address < ApplicationRecord
belongs_to :addressable, polymorphic: true
end
事件模型:
class Event < ApplicationRecord
has_one :address, as: :addressable
accepts_nested_attributes_for :address
end
事件控制器:
class EventsController < ApplicationController
#...stuff...
# GET /events/new
def new
@event = Event.new
@event.address = @event.build_address
#@event.address = Address.new(addressable: @event)
#@event.address = @event.create_address
#@event.address = @addressable.User.new
end
#...stuff...
你可以看到我尝试了多种方法来创建事件的地址,它们主要创建以下项目,使用 addressable
的方法会导致 Nil
崩溃。
#<Address id: nil, address: nil, latitude: nil, longitude: nil, addressable_type: "Event", addressable_id: nil>
事件表(使用 Simple_form gem):
<%= simple_form_for @event do |f| %>
<%= f.input :name %>
<%= f.input :description %>
<%= f.simple_fields_for :address do |address| %>
<%= render :partial => 'shared/address/form', :locals => {:f => address} %>
<% end %>
<%= f.button :submit %>
<% end %>
部分地址形式:
<!-- Google Maps Must be loaded -->
<% content_for :head do %>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCMh8-5D3mJSXspmJrhSTtt0ToGiA-JLBc&libraries=places"></script>
<% end %>
<div id="map"></div>
<%= f.input :address %>
<%= f.input :latitude %>
<%= f.input :longitude %>
表单呈现良好。当我尝试保存时,我得到
Started POST "/events" for 127.0.0.1 at 2017-07-01 16:06:23 -0400
Processing by EventsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"R0zlSs3UUNV3x8sQn5ocmE4jP12uOsFza7FezBAuhP4sw2MhF1OhixF8sAfDsLpfMEX7x5rhJ9HZfbKna8ncEA==", "event"=>{"name"=>"asd", "description"
=>"asd", "address_attributes"=>{"address"=>"asd", "latitude"=>"1", "longitude"=>"1"}}, "commit"=>"Create Event"}
(0.1ms) begin transaction
(0.1ms) rollback transaction
我一直在 new
页面上。如果我将 byebug
插入 create
并打印出 @event.errors
它会显示:
#<ActiveModel::Errors:0x007fb29c34a9a8 @base=#<Event id: nil, name: "asd", description: "asd", min_users: nil, max_users: nil, start_time: nil, recurring: nil, created_at: nil, upd
ated_at: nil>, @messages={:"address.addressable"=>["must exist"]}, @details={:"address.addressable"=>[{:error=>:blank}]}>
如何创建 address.addressable?如某些 SO 答案所建议的那样关闭需要验证的后果是什么?
运行 rake db:schema:dump,然后检查 db/schema.rb 中的文件,确保你有如下 2 个字段 * t.integer :addressable_id, * t.string :addressable_type 有关更多详细信息,请参阅 link 关于 Activerecord Polymorphic Associations,如果您的架构有问题,则可以 运行 迁移如下
t.references :addressable, polymorphic: true, index: true
由于事件通过多态关联有多个地址,您可以使用this link创建地址 下面是示例代码
@address = @event.addresses.build(attributes = {}, ...)
您可以使用@address 而不是@event.address
发现了问题并写了一篇 blog post 对此进行了深入讨论。基本上我遇到了 2 个不同的问题
1.The 我收到错误 - "address.addressable"=>["must exist"]
。 address.addressable 是 'parent' table 的元组 ID。在我的例子中,它是事件 ID。这个错误试图告诉我,当我们试图将它保存在控制器的创建函数中时,新地址中缺少这个外键。就像我在问题中所说的那样,您可以设置 optional:true
来忽略这个问题,并且在保存事件后它会以某种方式神奇地被填充。或者你可以在保存之前在创建函数中手动分配它。
def create
@event = Event.new(event_params)
@event.address.addressable = @event #<<<<<<<<<<< manually assign address.addressable
respond_to do |format|
if @event.save #Saves the event. Addressable has something to reference now, but validation does not know this in time
format.html { redirect_to @event, notice: 'Event was successfully created.' }
format.json { render :show, status: :created, location: @event }
else
#dont forget to remove the 'byebug' that was here
format.html { render :new }
format.json { render json: @event.errors, status: :unprocessable_entity }
end
end
end
2.Event ID 是一个字符串。在我的地址迁移中,我使用的是 t.references :addressable, polymorphic: true, index: true
和 addressable_id
整数类型的别名。我需要更改我的迁移以使用字符串 ID - 所以删除 references
行并添加它。
t.string :addressable_id, index: true
t.string :addressable_type, index: true
博客 post.
对此进行了更详细的介绍