質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby on Rails 6

Ruby on Rails 6は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Q&A

解決済

2回答

973閲覧

rails 中間テーブルに保存されず普通のテーブルに保存されます。中間テーブルに書き込む方法をご教授お願い致します。

hiromix

総合スコア7

Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby on Rails 6

Ruby on Rails 6は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

0グッド

0クリップ

投稿2022/02/05 14:33

rails で中間テーブルを使いたくて、RailsApplicationBuild Guidesを参考に構築しました。
コードは、上記のgithubを使っています。
1.4.3. サンプルアプリケーション

テーブル構成
以下の三つです。

  • product テーブル
  • categoryテーブル
  • product_categoryテーブル

挙動
投稿フォームからデータを入れて登録ボタンを押したら無事に反映されていたのですが、データベースを確認したところ、中間テーブルにデータが保存されていませんでした

保存されていたのはproduct でした。

model

productテーブル

# == Schema Information # # Table name: products # 商品 # # id :integer not null, primary key # code :string(10) not null # 商品コード # name :string(50) not null # 商品名 # name_kana :string(50) default(""), not null # 商品名カナ←削除 # price :integer not null # 商品価格←削除 # purchase_cost :integer not null # 仕入原価←削除 # availability :boolean not null # 販売可能フラグ←削除 # created_at :datetime not null # updated_at :datetime not null # class Product < ApplicationRecord has_many :product_categories has_many :categories, through: :product_categories accepts_nested_attributes_for :product_categories, allow_destroy: true validates :code, presence: true, length: { maximum: 10 } validates :name, presence: true, length: { maximum: 50 } end

categoryテーブル

# == Schema Information # # Table name: categories # カテゴリ # # id :integer not null, primary key # name :string(50) not null # カテゴリ名 # created_at :datetime not null # updated_at :datetime not null # class Category < ApplicationRecord has_many :product_categories has_many :products, through: :product_categories end

ProductCategoryモデル 中間テーブル

# == Schema Information # # Table name: product_categories # 商品カテゴリ # # id :integer not null, primary key # product_id :integer not null # 商品ID # category_id :integer not null # カテゴリID # created_at :datetime not null # updated_at :datetime not null # class ProductCategory < ActiveRecord::Base belongs_to :product belongs_to :category end

**

form/product.rb**

class Form::Product < Product # == Schema Information # # Table name: products # 商品 # # id :integer not null, primary key # code :string(10) not null # 商品コード # name :string(50) not null # 商品名 # name_kana :string(50) default(""), not null # 商品名カナ # price :integer not null # 商品価格 # purchase_cost :integer not null # 仕入原価 # availability :boolean not null # 販売可能フラグ # created_at :datetime not null # updated_at :datetime not null # REGISTRABLE_ATTRIBUTES = %i(code name) has_many :product_categories, class_name: 'Form::ProductCategory' end

form/product_category.rb

# # Table name: product_categories # 商品カテゴリ # # id :integer not null, primary key # product_id :integer not null # 商品ID # category_id :integer not null # カテゴリID # created_at :datetime not null # updated_at :datetime not null # class Form::ProductCategory < ProductCategory REGISTRABLE_ATTRIBUTES = %i(id product_id category_id _destroy) def selectable_categories Category.all end end

view

view/products/new このページから商品情報を登録します。

ここに言語を入力 <% content_for(:title) do %> 商品登録 <% end %> <%= render 'form', path: products_path, method: :post %>

view/products/_form

<div class="panel panel-default"> <div class="panel-body"> <div class="row"> <div class="col-sm-12"> <%= form_for(@product, url: path, method: method) do |f| %> <div class="col-sm-6"> <div class="form-group"> <label class="control-label" for="">商品コード</label> <%= f.text_field :code, class: 'form-control' %> </div> <div class="form-group"> <label class="control-label" for="">商品名</label> <%= f.text_field :name, class: 'form-control' %> </div> </div> <div class="col-sm-12"> <hr> <b>商品カテゴリ</b> <div class="text-right"> <%= link_to_add_association 'カテゴリを追加', f, :product_categories, class: 'btn btn-default', data: { association_insertion_node: '#detail-association-insertion-point', association_insertion_method: 'append' } %> </div> <table class="table table-list"> <thead> <tr> <th></th> <th></th> </tr> </thead> <tbody id='detail-association-insertion-point'> <div class="form-group"> <%= f.fields_for :product_categories do |od| %> <%= render 'product_category_fields', f: od %> <% end %> </div> </tbody> </table> </div> <div class="col-sm-12"> <div class="text-center"> <%= f.submit '登録', class: 'btn btn-primary' %> </div> </div> <% end %> </div><!-- /col-sm-12 --> </div><!-- /row --> </div><!-- /panel-body --> </div><!-- /panel --> ※商品コード、商品名以外は省いています。

view/products/index 登録後このページで表示されます。

<% content_for(:title) do %> 商品検索 <% end %> <% @products.each do |product| %> <li><%= product.name %></li> <% end %> ※元のコードでは商品を検索して表示させるものでしたが、ransakなどのgemインストールが必要でしたので検索機能は省いてます。登録したものだけ表示するようにしています。

view/products/_product_category_fields.html.erb

<tr class="nested-fields"> <%= f.hidden_field :id %> <td> <%= f.collection_select :category_id, f.object.selectable_categories, :id, :name, {}, class: 'form-control' %> </td> <td> <%= link_to_remove_association '削除', f, class: 'btn btn-default' %> </td> </tr>

controller

products_controller.rb

class ProductsController < ApplicationController def index # @q = Product.search @products = Product.all end def new @product = Form::Product.new end def edit @product = Form::Product.find(params[:id]) end def create @product = Form::Product.new(product_params) if @product.save redirect_to products_path, notice: "商品 #{@product.name} を登録しました。" else render :new end end def update @product = Form::Product.find(params[:id]) if @product.update_attributes(product_params) redirect_to products_path, notice: "商品 #{@product.name} を更新しました。" else render :edit end end private def search_params search_conditions = %i(code_cont name_cont) params.require(:q).permit(search_conditions) end def product_params params .require(:form_product) .permit( Form::Product::REGISTRABLE_ATTRIBUTES + [product_categories_attributes: Form::ProductCategory::REGISTRABLE_ATTRIBUTES] ) end end def search がありましたがこちら消してます。

routes.rb

resources :products do collection do get :search end end # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html end

schema

ActiveRecord::Schema.define(version: 2022_02_05_121124) do create_table "categories", force: :cascade do |t| t.string "name" t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false end create_table "product_categories", force: :cascade do |t| t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false t.integer "product", null: false t.integer "category", null: false t.integer "product_id", null: false t.integer "category_id", null: false t.index ["category_id"], name: "index_product_categories_on_category_id" t.index ["product_id"], name: "index_product_categories_on_product_id" end create_table "products", force: :cascade do |t| t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false t.string "code" t.string "name" end add_foreign_key "product_categories", "categories" add_foreign_key "product_categories", "products" end

コードは以上になります。
上記の通りに書き込むとproductテーブルに書き込まれてしまいます。
中間テーブルに書き込みたいのですがどのようにすればよいでしょうか?
どなたか中間テーブルに詳しい方教えていただけますでしょうか?
よろしくお願いいたします(__)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

追記

やりたいことは理解しました。及び 今回勉強したいのは 中間テーブルですね?
だとすると参考にしたサイトは不適当かも。FormObject とか viewにあとから追加可能とか、未知の領域の方が数が多い。
FormObjectなし、viewも予め関連の入力エリアが複数用意されている というところを探すのがよいかも、です。

さておき

  1. 「中間テーブルにデータが保存されていませんでした。保存されていたのはproduct でした。」

とありますが、中間テーブルにデータが保存されていないのはどう確認しましたか? 例えば rails c で 中間テーブルの中身の確認はしましたか?
2. 放送時刻を保存したいのでしたら、(1) 中間テーブルにその項目を追加する (2) viewにその入力エリアを用意する (3) product_categories_attributes: に追加する
でできます。


保存されていたのはproduct でした。

旧回答

>product_categoryテーブル→放送時間
ということでしたら、product_categoryテーブル に 放送時間 の項目を追加すれば良いのですが、
なんかデータ構造がおかしい。。。。

ドラマであるなら テレビ局は一意でしょうから、テレビ局はドラマの項目とし、1:多で放送時間を入れる のでは
それとも、
「なんとか系列の放送局が日本各地で同じドラマをやるから、それらを全部登録する」 ということでしょうか?

それから、モデル名は実態に合わせたほうがよいです。
及び
Form classを持ち出すほどの複雑なことではないと思うので、もっとシンプルな例を探しましょう。
及び
<%= form_for(@product, url: path, method: method) do |f| %> のところ。
@productが適正に設定されていれば url も method も不要です。あるとむしろややこしいかも。

投稿2022/02/06 14:08

編集2022/02/07 23:27
winterboum

総合スコア23333

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hiromix

2022/02/07 13:26

「なんとか系列の放送局が日本各地で同じドラマをやるから、それらを全部登録する」 ということでしょうか? はい、そうです。 他の方に返事した内容に似ますが、 ドラマタイトルのテーブルに作品名とテレビ局のカラムを用意して、放送時間を設定するとテレビ局だけで129局あります。日テレ系などの表記でひとくくりの放送時間にするものではございません。 >>それから、モデル名は実態に合わせたほうがよいです。 とりあえず中間テーブルを使ってみたかったのでソースコードのままにしています。 >>@productが適正に設定されていれば url も method も不要です。 ありがとうございます。こちらシンプルにしてみます。参考になりました。
hiromix

2022/02/08 06:52

「中間テーブルにデータが保存されていませんでした。保存されていたのはproduct でした。」 とありますが、中間テーブルにデータが保存されていないのはどう確認しましたか? 例えば rails c で 中間テーブルの中身の確認はしましたか? 中間テーブルの中身は確認しました。 その後、中間テーブルについて調べて controllerを下記に修正したところ中間テーブルに書き込まれました。 @product.product_categories.build 上記の件やwinterboum様のおっしゃる通り参考にしたサイトが不適当だと思いました。 こちら中間テーブルについて知識がほとんどありませんでしたので、 仕組みなどを含めて勉強した上であらためて作りたいと思います。 ありがとうございました!
guest

0

中間テーブルに書き込みたいのですが

何を書き込みたいのでしょうか?

このテーブルにはproduct_idとcategory_id(とRailsの慣習上存在するid、created_at、updated_at)しか列がなく、両者の紐付けをする以上のデータを書き込む余地は、そもそもありません。

投稿2022/02/06 00:25

maisumakun

総合スコア145184

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hiromix

2022/02/06 07:20 編集

お忙しいありがとうございます。 失礼しました。 たしかにそうですね。idのみしかかないことに気づきました。 元々ドラマの放送時間を作りたくてはじめたものです。 ドラマタイトルのテーブルに作品名とテレビ局のカラムを用意して、放送時間を設定するとテレビ局だけで129局ありました。そのほかの動画配信などを含めると横に伸び続けるのと、放送されるテレビ局は少ないのでほとんど空欄となるので中間テーブルが必要となりました。 テレビ番組の放送時間を中間テーブルに。 product テーブル→ドラマタイトル categoryテーブル→→テレビ局 product_categoryテーブル→放送時間 自分の環境下で作った時も中間テーブルに入らなかったので、上記のRailsApplicationBuild Guidesコードで中間テーブルに入れる練習をしようと思い、作ったのですがうまくできませんでした。 こちらの件ではご指摘いただいたidのみだったので、 一度カラムを増やしてみます。 お忙しい中ありがとうございます。
hiromix

2022/02/06 13:29 編集

Rails Application Build Guidesの「ProductCategoryモデル」をあらためて確認したところ、 下記のschemaの記載にもそもそも中間テーブルにid以外が書き込まれるようになっておらず、 中間テーブルにデータを入れる参考を間違えた可能性があります。 # == Schema Information # # Table name: product_categories # 商品カテゴリ # # id :integer not null, primary key # product_id :integer not null # 商品ID # category_id :integer not null # カテゴリID # created_at :datetime not null # updated_at :datetime not null # class ProductCategory < ActiveRecord::Base belongs_to :product belongs_to :category end product_idとcategory_idのほかにproductのcodeとnameのカラムも中間テーブルに追加して、動作確認をしたのですが、中間テーブルには何も書き込まれていませんでした。 product_id、category_idにも数字が入っておりませんでした。
maisumakun

2022/02/06 13:32

> product_idとcategory_idのほかにproductのcodeとnameのカラムも中間テーブルに追加して えっと、それはなぜ必要なのですか? (関連付けたproductから引いてくればいいだけなので、正規化を崩す形となる冗長な列です)
maisumakun

2022/02/07 07:49

> こちらのように作りたいためです。 当該の記事を読んだのですが、中間テーブルには紐付け用の列しかありません。
hiromix

2022/02/07 13:15

user_school ←中間テーブル new!!というところですが、 id user school 1 a A小学校 2 a B中学校 3 a C高校 4 a D大学 5 b A小学校 6 b B中学校 〜 〜 こちらレコードが作られていると思っていたのですが、 上記ページは紐づけのイメージを便宜上表示していたということでしょうか? それならば納得いたしました。
maisumakun

2022/02/07 13:27

> 上記ページは紐づけのイメージを便宜上表示していたということでしょうか? 単に間違えて名前を入れてしまっているだけです。
winterboum

2022/02/07 22:55

maisumakunさん、 このような例でForm object にする意味ありますかね? みな ARから継承しているし。 複雑にするだけでディメリットしか無いようにおもえるのですが。 中間テーブルの勉強でしたら、Form objectなしで作り直したほうが良いように思えます。 いかがでしょう。
hiromix

2022/02/08 06:39

winterboums様 Form object無しで放送時間の入れ方はありますか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問