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

时间:2021-04-10 19:58:50

标签: ruby-on-rails activerecord associations instance

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

我的 Item 可以属于许多 List,而我的 List 应该有许多 Item 因此,截至目前,我使用的是 {{1 }} 关联我的 has_and_belongs_to_manyItem 模型。

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

这是我当前的 Itemlists 架构和 items 关联所需的连接表 list_nominations - 我很确定我没有使用正确(has_and_belongs_to_many 中的 :points 属性将是跟踪 items 受欢迎程度的一种方式:

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 List 模型中的代码:

Item

有没有办法做到这一点,或者有没有关于更好的方法来跟踪 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 的多个实例的建议?

1 个答案:

答案 0 :(得分:0)

恐怕你的表不适合任何已知的方法,你可以实现你想要的,但这不是一个完美的也不是推荐的解决方案,你可以在许多 has_one 上指定主键lists 中的关联,但在 items 中不太可能将所有 lists 都包含在一个关联中,但您可以使用一个实例方法来查询 lists 并返回匹配的方法

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(您的表需要一个字段来正确地相互指向)

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

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

数据库:

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

以及此处 2 种方法之间的区别 https://guides.rubyonrails.org/association_basics.html#choosing-between-has-many-through-and-has-and-belongs-to-many