【问题标题】:Rails 4 - Polymorphic associationsRails 4 - 多态关联
【发布时间】:2016-04-05 19:05:17
【问题描述】:

我正在尝试在 Rails 4 中制作应用程序。

我有一个配置文件模型和一个地址模型。

这些协会是:

profile.rb

has_many :addresses, as: :addressable

地址.rb

 belongs_to :addressable, :polymorphic => true

地址是一个多态模型。

我有一个地址表格:

<%= simple_form_for(@address) do |f| %>
            <%= f.error_notification %>

            <div class="form-inputs">
                <div class="row">
                    <div class="col-xs-3">
                        <%= f.input :unit %>
                    </div>
                    <div class="col-xs-3 col-xs-offset-1">
                        <%= f.input :street_number %>
                    </div>
                    <div class="col-xs-3 col-xs-offset-1">
                        <%= f.input :street %>
                    </div>
                </div>

                <div class="row">
                    <div class="col-xs-3">
                        <%= f.input :building %>
                    </div>
                    <div class="col-xs-3 col-xs-offset-1">
                        <%= f.input :city %>
                    </div>
                    <div class="col-xs-3 col-xs-offset-1">
                        <%= f.input :region %>
                    </div>

                </div>

                <div class="row">
                    <div class="col-xs-3">
                        <%= f.input :zip %>
                    </div>
                    <div class="col-xs-3 col-xs-offset-1">
                        <%= f.input :country, priority: [ "Australia", "New Zealand", "United Kingdom" ] %>
                    </div>


                </div>

                <div class="row">
                    <div class="col-xs-3">
                        <%= f.input :main_address %>
                    </div>
                    <div class="col-xs-3 col-xs-offset-1">
                        <%= f.input :project_offsite %>
                    </div>


                </div>



            </div>

            <div class="form-actions">
                <%= f.button :submit, :class => "formsubmit" %>
            </div>
            <% end %>

我尝试创建一个地址并保存它。然后我检查它是否在 rails 控制台中。出了点问题,因为 rails 控制台显示如下:

#<Address id: 1, unit: "", building: "", street_number: "34", street: "f", city: "sdfasdf", region: "asdf", zip: "2000", country: "GB", main_address: nil, project_offsite: nil, time_zone: nil, latitude: nil, longitude: nil, addressable_id: nil, addressable_type: nil, created_at: "2015-12-30 00:07:00", updated_at: "2015-12-30 00:17:00"> 

可寻址的id和可寻址的类型都是nil。

他们应该将引用返回到配置文件或相关模型所在的任何位置。

设置此流程是否缺少步骤?

这个视频(第 3.40 分钟)说 rails 会自动处理填充多态模型的 type 和 id 字段。 https://gorails.com/episodes/comments-with-polymorphic-associations?autoplay=1

当我尝试从 rails 控制台创建新地址时,我输入:

Address.create(addressable: Address.first, profile_id: "1", country: "AU")

控制台错误是:

ActiveRecord::UnknownAttributeError: unknown attribute 'profile_id' for Address

我的地址表有一个 addressable_id 键,我的配置文件模型有 has_many :addresses, as: :addressable

我无法理解导致错误的原因

另一个尝试

因此,根据我从以下建议中收集到的信息,我需要做一些事情来让 address 知道它属于个人资料。

我还发现了这篇文章,它列出了一个示例,说明在配置文件控制器中需要发生什么以使事情与多态关联一起工作: http://6ftdan.com/allyourdev/2015/02/10/rails-polymorphic-models/

我将配置文件控制器中的新操作更改为(包括addresses.build):

 def new
    @profile = Profile.new
    @profile.qualifications.build
    @profile.visions.build
    @profile.personalities.build
    @profile.addresses.build

    authorize @profile
  end

我将嵌套属性添加到配置文件模型中的地址关联:

has_many :addresses, as: :addressable
    accepts_nested_attributes_for :addresses,  reject_if: :all_blank, allow_destroy: true

我更改了我的地址表格: - 从 form_for 到 fields_for; - 将其重命名为 _address_fields.html.erb;和 - 打开 div 标签:

<div class="nested-fields">

在我的个人资料表单中,我将链接添加到部分表单:

              Your addresss
            </div>
            <%= f.simple_fields_for :addresses do |f| %>

              <%= render 'addresses/address_fields', f: f %>  
            <% end %>
            </div>
          <div class="row">
            <div class="col-md-6">

               <%= link_to_add_association 'Add an address', f, :addresses, partial: 'addresses/address_fields' %>

            </div>

所有这一切都在 Jeiwan 对这篇帖子的回答中列出:Rails - Cocoon gem - Nested Forms

然后,当我尝试所有这些时,我得到了这个错误:

ActiveRecord::RecordNotUnique in ProfilesController#update
PG::UniqueViolation: ERROR: duplicate key value violates unique constraint "index_addresses_on_addressable_type_and_addressable_id" DETAIL: Key (addressable_type, addressable_id)=(0, 1) already exists. : INSERT INTO "addresses" ("unit", "building", "street_number", "street", "city", "region", "zip", "country", "addressable_id", "addressable_type", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) RETURNING "id"

错误指向profiles控制器中的更新方法:

 def update
    respond_to do |format|
      if @profile.update(profile_params)
        format.html { redirect_to @profile }
        format.json { render :show, status: :ok, location: @profile }
      else

我发现这篇文章描述了用户的类似问题,但在我更改数据库之前,我想尝试了解发生了什么。

Rails auto-assigning id that already exists

另一件奇怪的事情是,当我查看控制台中创建的最后一个地址时,它会显示:

#<Address id: 6, unit: "", building: "", street_number: "34", street: "asdf", city: "asdf", region: "add", zip: "2111", country: "AU", main_address: nil, project_offsite: nil, time_zone: nil, latitude: nil, longitude: nil, addressable_id: 1, addressable_type: 0, created_at: "2016-01-01 22:01:31", updated_at: "2016-01-01 22:01:31">]> 

记录现在有一个 addressable_id 但没有 addressable_type。填充此字段是否需要额外的东西?

【问题讨论】:

    标签: ruby-on-rails polymorphic-associations


    【解决方案1】:

    此表单没有 addressable id/type 字段,因此除非您在控制器中明确设置它们或相关对象,否则将得到 nil 是预期的。

    在模型中定义关系只是说明对象可以以这种方式关联,而不是设置实际值。实际上 - rails 有很多神奇之处,但它无法猜测哪个profile 是哪个地址的所有者

    【讨论】:

    • 但是如何设置它们?
    • @user2860931 只需将它们声明为隐藏或选择可寻址,或者如果您稍后能够设置它,请保持原样,只需将 validate addressable_id 跳过为 nil。
    • 但是如果地址表单属于配置文件,并且编辑配置文件路径导致地址表单,那不是链接。如果我让用户选择 id,那么如果要求用户选择他们自己的个人资料 id 来添加地址,那么在表单中看起来会很奇怪。没有一个示例显示需要隐藏字段才能使其正常工作。请你给我一个链接到这个例子吗?非常感谢
    • 这个视频说 rails 会自动处理填充多态 id 字段gorails.com/episodes/…
    【解决方案2】:

    你对polymorphic associations感到困惑:

    使用多态关联,一个模型可以在一个关联上属于多个其他模型

    这意味着ActiveRecord自动分配Address 模型的addressable_typeaddressableid,具体取决于创建它的关联模型。

    例如...

    #app/models/profile.rb
    class Profile < ActiveRecord::Base
       has_many :addresses, as: :addressable
    end
    
    #app/models/address.rb
    class Address < ActiveRecord::Base
       belongs_to :addressable, polymorphic: true
    end
    

    以上意味着每次创建个人资料时,您都可以为其创建或分配地址。如果您有其他型号 (users),您也可以这样做。 addressable_id & addressable_type 将自动分配到 address 记录中:

    #app/controllers/profiles_controller.rb
    class ProfilesController < ApplicationController
       def create
           @profile = Profile.new profile_params
           @profile.save
       end
    
       private
    
       def profile_params
          params.require(:profile).permit(...)
       end
    end
    

    --

    您遇到的主要问题是您对哪个模型具有关联的polymorphic 元素感到困惑。

    他们应该将引用返回到配置文件或相关模型所在的任何位置。

    @profile = Profile.find x
    @address = @profile.addresses.new address_params ...
    

    这将为profile 模型分配addressable_idaddressable_type,允许您代表profile 创建地址。

    @address = current_user.addresses.new address_params
    

    这个完全相同的代码将允许您为用户创建一个地址(相同的模型、相同的关联等)。


    要回答您的问题,您需要围绕相关模型确定对象创建范围:

    @address = Address.create(country: "AU")
    
    @profile = Profile.find 1
    @profile.addresses << @address
    

    你也可以这样做:

    @profile = Profile.find 1
    @profile.addresses.create country: "AU"
    

    --

    如果您希望地址“依赖”于其他地址,则需要添加 parent_id 列,并使用 acts_as_tree 或其他层次结构宝石。

    【讨论】:

    • 嗨,丰富。谢谢你。我不确定您对如何将地址链接到个人资料的建议。我是否需要在配置文件控制器新操作中添加一些内容来构建 profile.address?查看您在上面列出的这一行“@address = @profile.addresses.new address_params ...” - 我不确定在我的配置文件控制器中的何处使用它。我在任何资源中都找不到这样的例子。
    • 我也对你的评论感到困惑,我对哪个模型具有关联的多态元素感到困惑。我认为我的关联设置正确 - 我看不出您的示例和我的代码之间的区别
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-16
    • 1970-01-01
    • 2016-03-20
    • 2014-09-12
    相关资源
    最近更新 更多