一个/或关联与两个单独行的多态关联,其中一个为空

时间:2022-02-10 21:06:25

I'm new to rails and was trying to implement a polymorphic association. Basically, I have a device object which can belong to either a outlet or a port, but not both. From my understanding, a polymorphic association would be the way to do this, so I modeled it like this:

我是rails的新手,并试图实现多态关联。基本上,我有一个设备对象,可以属于插座或端口,但不能同时属于两者。从我的理解,多态关联将是这样做的方式,所以我这样建模:

class Device < ApplicationRecord
    belongs_to :io, polymorphic: true
end

class Outlet < ApplicationRecord
    has_one :device, as: :io
end

class Port < ApplicationRecord
  has_one :device, as: :io
end


  create_table "devices", force: :cascade do |t|
        ...
        t.integer "io_id"
        t.index ["io_id"], name: "index_devices_on_io_id"
      end

Now, I ran into some trouble trying to assign an outlet or port to the device's io:

现在,我在尝试为设备的io分配插座或端口时遇到了一些麻烦:

can't write unknown attribute io_type

无法写入未知属性io_type

  @outlet = Outlet.where(id: @outlet_id).first

  @device.io = @outlet

  if @device.save
  redirect_to @device

which is from

来自

class DevicesController < ApplicationController
    def new
        @device = Device.new(io_id: params[:io_id])
    end

    def create
        @outlet_id = params[:device][:io_id]
        @device = Device.new(device_params)

        @outlet = Outlet.where(id: @outlet_id).first

        @device.io = @outlet

        if @device.save
        redirect_to @device
      else
        render 'new'
      end

  end

Now, I will gladly accept some help on why this error was thrown, but that's not my primary question. I had a thought while debugging this-- does it even matter if I don't use a polymorphic association here? Would it also be fine just to create two separate associations on my device table, one pointing to the port table and the other to the outlet table and make them both optional? One would remain null and the other would be assigned, and then I could check which field != null in my business logic. Will I run into problems down the road going this route?

现在,我很乐意接受一些关于为什么会抛出此错误的帮助,但这不是我的主要问题。调试时我有一个想法 - 如果我不在这里使用多态关联,它是否重要?在我的设备表上创建两个单独的关联也是可以的,一个指向端口表,另一个指向outlet表并使它们都是可选的?一个将保持为null而另一个将被分配,然后我可以检查我的业务逻辑中的哪个字段!= null。我会在这条路上遇到问题吗?

1 个解决方案

#1


1  

Device needs both an io_id and an io_type. Otherwise, how would Device know what kind of thing the io_id belongs to?

设备需要io_id和io_type。否则,设备如何知道io_id属于什么样的东西?

Currently, as shown by your migration, you only have io_id. And so, you're getting the unknown attribute error for io_type.

目前,如您的迁移所示,您只有io_id。因此,您将获得io_type的未知属性错误。

You should add io_type to your table and you should be good to go.

您应该将io_type添加到您的表中,您应该很高兴。

I suggest you modify your create action to be more like (with some comments):

我建议你修改你的创建动作更像(带一些注释):

class DevicesController < ApplicationController
  def new
    @device = Device.new(io_id: params[:io_id])
  end

  def create

    # how do you know the :io_id is for an Outlet and not a Port?
    # if you add a hidden field that includes io_type, so that
    # params[:device] = {io_id: x, io_type: 'Outlet'}, then you 
    # should be able to do something like:
    @io = params[:device][:io_type].constantize.find_by(id: params[:device][:io_id])

    # the has_one association provides the build_device method.
    # if you use this method, then io_id and io_type will 
    # automatically be set on @device
    @device = @io.build_device(device_params)

    if @device.save
      redirect_to @device
    else
      render 'new'
    end

end

#1


1  

Device needs both an io_id and an io_type. Otherwise, how would Device know what kind of thing the io_id belongs to?

设备需要io_id和io_type。否则,设备如何知道io_id属于什么样的东西?

Currently, as shown by your migration, you only have io_id. And so, you're getting the unknown attribute error for io_type.

目前,如您的迁移所示,您只有io_id。因此,您将获得io_type的未知属性错误。

You should add io_type to your table and you should be good to go.

您应该将io_type添加到您的表中,您应该很高兴。

I suggest you modify your create action to be more like (with some comments):

我建议你修改你的创建动作更像(带一些注释):

class DevicesController < ApplicationController
  def new
    @device = Device.new(io_id: params[:io_id])
  end

  def create

    # how do you know the :io_id is for an Outlet and not a Port?
    # if you add a hidden field that includes io_type, so that
    # params[:device] = {io_id: x, io_type: 'Outlet'}, then you 
    # should be able to do something like:
    @io = params[:device][:io_type].constantize.find_by(id: params[:device][:io_id])

    # the has_one association provides the build_device method.
    # if you use this method, then io_id and io_type will 
    # automatically be set on @device
    @device = @io.build_device(device_params)

    if @device.save
      redirect_to @device
    else
      render 'new'
    end

end