如何通过has_one关系建立此has_many关系?

时间:2019-01-11 08:59:22

标签: ruby-on-rails ruby database

请原谅我的英语不完美。

我希望能够使用一个theme创建一个subcategory(并且子类别具有一个主题),并将此theme链接到多个categories。我希望我可以做Theme.first.categoriesCategory.first.themes

在主题表中,我只保存名称和子弹。在子类别表中,我保存了描述,页面标题等,因为每个类别将具有名称相同但描述不同的主题。

例如,我可以有两个类别,例如“法语到英语”和“意大利语到中文”。这些类别都将具有一个名为“科学”的主题,但具有不同的描述。

当前,我可以创建一个主题,但只能创建一个类别。例如,如果我选择两个类别,则会出现错误:can't modify frozen Hash

theme.rb:

    class Theme < ApplicationRecord
      has_one(:subcategory, dependent: :destroy)
      has_many(:categories, through: :subcategory)

      accepts_nested_attributes_for :subcategory
    end

subcategory.rb:

    class Subcategory < ApplicationRecord
      belongs_to(:category)
      belongs_to(:theme)
    end

category.rb:

    class Category < ApplicationRecord
      has_many(:subcategories, dependent: :destroy)
      has_many(:themes, through: :subcategories)
    end

schema.rb:

    create_table "themes", force: :cascade do |t|
      t.string "name", null: false
      t.string "slug"
      t.datetime "created_at", null: false
      t.datetime "updated_at", null: false
    end

    create_table "subcategories", force: :cascade do |t|
      t.text "description"
      t.string "page_title"
      t.string "meta_description"
      t.string "h1_title"
      t.bigint "category_id"
      t.bigint "theme_id"
      t.datetime "created_at", null: false
      t.datetime "updated_at", null: false
      t.index ["category_id"], name: "index_subcategories_on_category_id"
      t.index ["theme_id"], name: "index_subcategories_on_theme_id"
    end

    create_table "categories", force: :cascade do |t|
      t.string "name", null: false
      t.datetime "created_at"
      t.datetime "updated_at"
      t.string "slug"
      t.text "description"
      t.string "page_title"
      t.string "meta_description"
      t.string "h1_title"
      t.string "source_language"
      t.string "target_language"
    end

themes_controller.rb:

# frozen_string_literal: true

    module Admin
      class ThemesController < AdminController
        load_and_authorize_resource except: :update
        before_action(:load_categories, only: %i[new edit])
        before_action(:load_theme, only: :update)

        def index
          @themes = Theme.all.to_a
        end

        def new
          @theme.build_subcategory
        end

        def create
          @theme = Theme.new(theme_params)
          if @theme.save
            redirect_to(admin_themes_url, notice: 'Theme successfully created')
          else
            render(:new)
          end
        end

        def edit
        end

        def update
          if @theme.update(theme_params)
            redirect_to(admin_themes_url, notice: 'Theme successfully edited')
          else
            render(:edit)
          end
        end

        def destroy
          @theme.destroy
          redirect_to(admin_themes_url, notice: 'Theme successfully deleted')
        end

      private

        def theme_params
          params.require(:theme).permit(
            :id,
            :name,
            :slug,
            subcategory_attributes: %i[description h1_title page_title meta_description],
            category_ids: [],
          )
        end

        def load_categories
          @categories = Category.all.to_a
        end

        def load_theme
          @theme = Theme.find_by(slug: params[:id])
        end
      end
    end

和我的表单:


    = simple_form_for([:admin, @theme]) do |f|
      = f.input(:name, autofocus: true)
      = f.simple_fields_for :subcategory_attributes, @theme.subcategory do |s|
        = s.input(:h1_title)
        = s.input(:description)
        = s.input(:page_title)
        = s.input(:meta_description)
      = f.input(:category_ids, collection: @categories.map { |cat| [cat.name, cat.id] }, as: :check_boxes, wrapper: :vertical_radio_and_checkboxes)
      = f.button(:submit , class: 'btn btn-primary')

日志:

0:39:39 server.1 | Started POST "/admin/themes" for ::1 at 2019-01-11 10:39:39 +0100
10:39:39 server.1 | Processing by Admin::ThemesController#create as HTML
10:39:39 server.1 |   Parameters: {"utf8"=>"✓", "authenticity_token"=>"6p2oxZvOlFJHYvAeYbkjjOrGGk8Y5GrnFOTBuQEmxTcMIhgfK32N2/ZGabLYmoW0pHiUaX6hVqb/EeuTgbr55g==", "theme"=>{"name"=>"rerezre", "subcategory_attributes"=>{"h1_title"=>"reez", "description"=>"rezer", "page_title"=>"rezrez", "meta_description"=>"rezerez"}, "category_ids"=>["", "1", "2"]}, "commit"=>"Créer un(e) Theme"}
10:39:39 server.1 |   User Load (1.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 7], ["LIMIT", 1]]
10:39:39 server.1 |   ↳ app/controllers/application_controller.rb:93
10:39:39 server.1 |   Category Load (0.8ms)  SELECT "categories".* FROM "categories" WHERE "categories"."id" IN ($1, $2)  [["id", 1], ["id", 2]]
10:39:39 server.1 |   ↳ /Users/robin/.rvm/gems/ruby-2.5.1/gems/activerecord-5.2.1.1/lib/active_record/log_subscriber.rb:98
10:39:39 server.1 |    (0.3ms)  BEGIN
10:39:39 server.1 |   ↳ /Users/robin/.rvm/gems/ruby-2.5.1/gems/activerecord-5.2.1.1/lib/active_record/log_subscriber.rb:98
10:39:39 server.1 |    (0.3ms)  COMMIT
10:39:39 server.1 |   ↳ /Users/robin/.rvm/gems/ruby-2.5.1/gems/activerecord-5.2.1.1/lib/active_record/log_subscriber.rb:98
10:39:39 server.1 |   CACHE Category Load (0.0ms)  SELECT "categories".* FROM "categories" WHERE "categories"."id" IN ($1, $2)  [["id", 1], ["id", 2]]
10:39:39 server.1 |   ↳ app/controllers/admin/themes_controller.rb:18
10:39:39 server.1 |    (0.2ms)  BEGIN
10:39:39 server.1 |   ↳ app/controllers/admin/themes_controller.rb:18
10:39:39 server.1 |    (0.1ms)  COMMIT
10:39:39 server.1 |   ↳ app/controllers/admin/themes_controller.rb:18
10:39:39 server.1 |    (0.1ms)  BEGIN
10:39:39 server.1 |   ↳ app/controllers/admin/themes_controller.rb:19
10:39:39 server.1 |   Category Exists (0.5ms)  SELECT  1 AS one FROM "categories" WHERE LOWER("categories"."name") = LOWER($1) AND "categories"."id" != $2 LIMIT $3  [["name", "Français à anglais"], ["id", 1], ["LIMIT", 1]]
10:39:39 server.1 |   ↳ app/controllers/admin/themes_controller.rb:19
10:39:39 server.1 |   Category Exists (0.5ms)  SELECT  1 AS one FROM "categories" WHERE LOWER("categories"."name") = LOWER($1) AND "categories"."id" != $2 LIMIT $3  [["name", "Italien à chinois"], ["id", 2], ["LIMIT", 1]]
10:39:39 server.1 |   ↳ app/controllers/admin/themes_controller.rb:19
10:39:39 server.1 |   Theme Create (0.7ms)  INSERT INTO "themes" ("name", "slug", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id"  [["name", "rerezre"], ["slug", "rerezre"], ["created_at", "2019-01-11 09:39:39.193694"], ["updated_at", "2019-01-11 09:39:39.193694"]]
10:39:39 server.1 |   ↳ app/controllers/admin/themes_controller.rb:19
10:39:39 server.1 |   Subcategory Create (0.5ms)  INSERT INTO "subcategories" ("description", "page_title", "meta_description", "h1_title", "category_id", "theme_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING "id"  [["description", "rezer"], ["page_title", "rezrez"], ["meta_description", "rezerez"], ["h1_title", "reez"], ["category_id", 2], ["theme_id", 24], ["created_at", "2019-01-11 09:39:39.196215"], ["updated_at", "2019-01-11 09:39:39.196215"]]
10:39:39 server.1 |   ↳ app/controllers/admin/themes_controller.rb:19
10:39:39 server.1 |   Category Exists (0.3ms)  SELECT  1 AS one FROM "categories" WHERE LOWER("categories"."name") = LOWER($1) AND "categories"."id" != $2 LIMIT $3  [["name", "Français à anglais"], ["id", 1], ["LIMIT", 1]]
10:39:39 server.1 |   ↳ app/controllers/admin/themes_controller.rb:19
10:39:39 server.1 |    (0.2ms)  ROLLBACK
10:39:39 server.1 |   ↳ app/controllers/admin/themes_controller.rb:19
10:39:39 server.1 | Completed 500 Internal Server Error in 32ms (ActiveRecord: 7.0ms)
10:39:39 server.1 |
10:39:39 server.1 |
10:39:39 server.1 | can't modify frozen Hash excluded from capture: Not configured to send/capture in environment 'development'
10:39:39 server.1 |
10:39:39 server.1 | FrozenError (can't modify frozen Hash):
10:39:39 server.1 |
10:39:39 server.1 | app/controllers/admin/themes_controller.rb:19:in `create'

我知道如果我想做自己想做的事,关系就会有问题,但是我不知道该怎么办。

请有人可以帮助我吗?

1 个答案:

答案 0 :(得分:1)

这里有一个概念上的问题。 由于ThemeSubcategory具有一对一的关系,而CategoryTheme具有一对多的关系Category和{{1}之间的传递关系}不能多对多。为此,Theme必须与Subcategory至少具有一对多关系。

换句话说: 每个主题只有一个子类别,每个子类别只有一个类别,因此每个主题到子类别都只有一个类别。 如果您希望某个主题具有多个类别(通过子类别),则应允许该主题具有多个子类别。