如何在 Rails 中将一个模型的实例设置为另一个模型的属性?

How to set an instance of a model as an attribute of another model in Rails?

我是 Rails 的新手,正在开发一款允许用户制作 List 的应用程序,其中包含他们在某个类别中排名前 5 的 Item。我遇到的主要问题是如何跟踪 List 订单(应该允许更改并且每个 User 都不同)?

我的 Item 可以属于很多 List 而我的 List 应该有很多 Item 所以,截至目前,我正在使用 has_and_belongs_to_many 我的 ItemList 模型的关联。

我现在跟踪列表顺序的想法是让我的 @list 有 5 个属性:一个对应列表中的每个排名(即 :first, :second, :third, :fourth, :fifth),我正在尝试将 @item 实例关联到 @list 属性(即 @list.first = @item1, @list.second = @item2 等)。现在我将 @list 属性保存到 @item ID (@list.first = 1),但我希望能够调用方法 .first.second等等,并直接指向特定的 Item 实例。

这是我当前的 listsitems 架构以及 has_and_belongs_to_many 关联所需的连接 table list_nominations - 我是很确定我没有正确使用(items 中的 :points 属性将是跟踪 item:

流行度的一种方式
create_table "lists", force: :cascade do |t|
    t.integer "user_id"
    t.integer "category_id"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.string "first"
    t.string "second"
    t.string "third"
    t.string "fourth"
    t.string "fifth"
  end

create_table "items", force: :cascade do |t|
    t.string "name"
    t.integer "category_id"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.integer "points", default: 0
  end

这是目前在我的 ListItem 模型中的代码:

class List < ApplicationRecord
    belongs_to :user 
    belongs_to :category
    has_and_belongs_to_many :items
end

class Item < ApplicationRecord
    belongs_to :category
    has_and_belongs_to_many :lists
end

有没有办法做到这一点,或者有什么建议可以更好地跟踪 List 订单,而无需创建相同 Item 的多个实例?

恐怕你的 table 不适合任何已知的方法,你可以实现你想要的,但这不是一个完美的 也不是推荐的 解决方案,您可以在 lists 内的许多 has_one 关联上指定主键,但在 items 中不太可能在一个关联中拥有所有 lists 但您可以使用实例方法哪个查询 lists 和 returns 匹配的

hacky 解决方案:


class List < ApplicationRecord
    belongs_to :user 
    belongs_to :category

    has_one :first_item, primary_key: :first, class_name: "Item"
    has_one :second_item, primary_key: :second, class_name: "Item"
    has_one :third_item, primary_key: :third, class_name: "Item"
    has_one :fourth_item, primary_key: :fourth, class_name: "Item"
    has_one :fifth_item, primary_key: :fifth, class_name: "Item"
end

class Item < ApplicationRecord
    belongs_to :category

    def lists
        List.where(
            "first = ? OR second = ? OR third = ? OR fourth = ? OR fifth = ?", self.id, self.id, self.id, self.id, self.id
        )
    end
end

您可以在此处阅读有关如何通过 has_and_belongs_to_many 关联创建多对多关系的信息:https://guides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association(您的 table 需要一个字段来正确指向每个其他)

我建议您遵循 many-to-many through 关系指南(单传递关联):

您将需要 1 个额外的 table 因为您要跟踪订单(第一、第二等)

数据库:

create_table "lists", force: :cascade do |t|
    .. all your other fields without first,second, etc..
end

create_table "items", force: :cascade do |t|
    .. all your other fields
end

create_table "lists_items", force: :cascade do |t|
    t.integer "list_id"
    t.integer "item_id"
    t.integer "rank" there is where you will store your order (first, second ..) bas as an integer
end

型号:

class ListsItem < ApplicationRecord
    belongs_to :list
    belongs_to :item
end

class List < ApplicationRecord
    belongs_to :user 
    belongs_to :category
    has_many :lists_items, -> { order(:rank) }, limit: 5
    has_many :items, through: :lists_items
end

class Item < ApplicationRecord
    belongs_to :category
    has_many :lists_items
    has_many :lists, through: :lists_items
end

您可以通过 has_many 通过此处 https://guides.rubyonrails.org/association_basics.html#the-has-many-through-association

阅读更多关于多对多的信息

这两种方法的区别在这里https://guides.rubyonrails.org/association_basics.html#choosing-between-has-many-through-and-has-and-belongs-to-many