🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails 6

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

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Q&A

解決済

1回答

2815閲覧

collection_check_boxesのデータがテーブルに保存されず困っています

退会済みユーザー

退会済みユーザー

総合スコア0

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails 6

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

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

0グッド

0クリップ

投稿2020/12/05 13:47

編集2020/12/05 13:53

前提・実現したいこと

Ruby on Rails
ActiveHashモデルのデータを用いてcollection_check_boxesで選択した複数の値を保存させたいです。

機能の目的は、自宅にある調味料をユーザーデータとして登録させたいというものです。
調味料のデータは頻繁に変わるものではないためActiveHashを用いて実装しようとしています。

発生している問題・エラーメッセージ

エラーメッセージは出ずに、createアクションで定義した保存できた場合、の条件分岐処理としてトップページに戻っても保存はできていません。

MySQLの調味料テーブル(seasonings)を確認すると、user_idはちゃんと紐付いた状態でレコードは追加されているのですが、collection_check_boxesで選択した値はsalt_sugar_idカラムに保存されずNULLになっています。

試したこと

crateアクションをbinding.pryで止めてターミナルログを確認し、salt_sugar_idカラムのパラメーターに問題があるとわかり、以下のことを試しました。

  • salt_sugar_idカラムに関係する記述すべてに誤字脱字はないか確認しました
  • バリデーションでnumericality: { other_than: 1 } をしている状態で、salt_sugar_idの中に空白""の値も入っているのも原因かと推測し、SaltSugarモデルself.dataのデフォルト部分を削除してみました
  • 複数の値を保存させたいことから、belongs_toのアソシエーションも間違っている可能性を考え、has_manyで検証しましたがNoMethodErrorになります。
  • permit!メソッドにしてみました。ターミナルログにはパラメーターのエラー文は出なくなったのですが、MySQLに値は保存されず保存できなかったときのページ遷移になります。

以下の情報以外に必要次項等ありましたらすぐに補足させていただきます。
直接的ではなくても、考え方やヒントだけでもご教示いただけたら嬉しいです。
宜しくお願い致します。

Started POST "/seasonings" for ::1 at Processing by SeasoningsController#create as HTML Parameters: {"authenticity_token"=>"HgwBaS0yU0S6Qf1kCr3IQ/k2X0OK9KlIxBz237TYrXLEjll3/02oSDL6qsJqGasb3XOUHcmhvX/ct8DegVOPPQ==", "seasoning"=>{"salt_sugar_id"=>["", "7", "8"]}, "commit"=>"登録"} Unpermitted parameter: :salt_sugar_id User Load (0.2ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 2 ORDER BY `users`.`id` ASC LIMIT 1 ↳ app/controllers/seasonings_controller.rb:25:in `seasoning_params' (0.2ms) BEGIN ↳ app/controllers/seasonings_controller.rb:13:in `create' User Load (0.4ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1 ↳ app/controllers/seasonings_controller.rb:13:in `create' (0.2ms) ROLLBACK ↳ app/controllers/seasonings_controller.rb:13:in `create' Rendering seasonings/new.html.erb within layouts/application Rendered shared/_header.html.erb (Duration: 0.2ms | Allocations: 133) Rendered shared/_footer.html.erb (Duration: 0.0ms | Allocations: 5) Rendered seasonings/new.html.erb within layouts/application (Duration: 1.6ms | Allocations: 1372) [Webpacker] Everything's up-to-date. Nothing to do Completed 200 OK in 53ms (Views: 23.3ms | ActiveRecord: 1.0ms | Allocations: 36486)

該当のソースコード

カラム名はsalt_sugarのみ抜粋し他は省略させていただいてます
config/routes.rb

ruby

1Rails.application.routes.draw do 2 devise_for :users 3 root to: 'seasonings#index' 4 get 'rakuten_search' => 'seasonings#index' 5 resources :seasonings, only:[:index, :new, :create] 6 resources :users, only:[:show] 7end

app/controllers/seasonings_controller.rb

ruby

1class SeasoningsController < ApplicationController 2 3 def index 4 @categories = RakutenWebService::Recipe.large_categories 5 @recipes = @categories.first.ranking 6 end 7 8 def new 9 @seasoning = Seasoning.new 10 end 11 12 def create 13 @seasoning = Seasoning.create(seasoning_params) 14 if @seasoning.save 15 binding.pry 16 redirect_to action: :index 17 else 18 render :new 19 end 20 end 21 22 private 23 24 def seasoning_params 25 params.require(:seasoning).permit(:salt_sugar_id).merge(user_id: current_user.id) 26 end 27 28end

app/models/seasoning.rb

ruby

1class Seasoning < ApplicationRecord 2 belongs_to :user 3 4 extend ActiveHash::Associations::ActiveRecordExtensions 5 belongs_to_active_hash :salt_sugar 6 7 validates :salt_sugar_id, numericality: { other_than: 1 } 8 9end

app/models/user.rb

ruby

1class User < ApplicationRecord 2 devise :database_authenticatable, :registerable, 3 :recoverable, :rememberable, :validatable 4 5 has_one :seasoning 6 has_one_attached :image 7 8 with_options presence: true do 9 validates :nickname 10 validates :password, length: { minimum: 8 }, format: { with: /\A(?=.*?[a-z])(?=.*?\d)[a-z\d]+\z/i } 11 end 12end

app/models/salt_sugar.rb ActiveHash model

ruby

1class SaltSugar < ActiveHash::Base 2 self.data = [ 3 # { id: 1, name: '--' }, 4 { id: 2, name: '塩' }, 5 { id: 3, name: '岩塩' }, 6 { id: 4, name: '藻塩' }, 7 { id: 5, name: '白砂糖' }, 8 { id: 6, name: '黒糖' }, 9 { id: 7, name: 'きび砂糖' }, 10 { id: 8, name: 'オリゴ糖' }, 11 ] 12 13 include ActiveHash::Associations 14 has_many :seasonings 15 16end

app/seasonings/new.html.rb

ruby

1<div id='home', class='big-bg'> 2 <%= render 'shared/header' %> 3 4 <div class='main-content'> 5 <div class='form-box'> 6 <div class='list'> 7 <h3><%= link_to "uchino_aji", "/", class: 'main-subtitle' %></h3><br /> 8 <h2>うちの調味料登録</h2> 9 10 <%= form_with model: @seasoning, url: seasonings_path, method: :post, local: true do |f| %> 11 12 <div class="form"> 13 <span class='optional'>(任意)</span> 14 <%= f.label "塩・砂糖", class: 'form-label' %><br /> 15 <%= f.collection_check_boxes(:salt_sugar_id, SaltSugar.all, :id, :name, {}, {class: 'check_box', id:'salt-sugar'}) %> 16 </div> 17 18 <div class="actions"> 19 <%= f.submit "登録", class: 'recipe-detail-btn' %> 20 </div> 21 <% end %> 22 23 </div> 24 </div> 25 </div> 26</div> 27<%= render 'shared/footer' %>

db/migrate/XXXXX_craate_seasonings.rb

ruby

1class CreateSeasonings < ActiveRecord::Migration[6.0] 2 def change 3 create_table :seasonings do |t| 4 t.references :user, null:false, foreign_key: true 5 t.integer :salt_sugar_id 6 t.timestamps 7 end 8 end 9end

補足情報(FW/ツールのバージョンなど)

GitHub(エラー部分は反映できていない状態です)
rails 6.0.0
mysql2 0.5.3
gem 'active_hash'

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

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

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

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

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

guest

回答1

0

ベストアンサー

ログに以下の記述がありますので、params[:salt_sugar_id] が弾かれてます。

Unpermitted parameter: :salt_sugar_id

以下のようにすると:salt_sugar_idが通ります。

ruby

1params.require(:seasoning).permit(:salt_sugar_id => []).merge(user_id: current_user.id)

ただ、seasoning の salt_sugar_id カラムに配列は保存できないと思います。

選択された salt_sugar_id の数だけ seasoning を作成するのであれば、
salt_sugar_id を ループで回して seasoning を create します。

seasoning がひとつで、それに紐づけられる salt_sugar が複数(seasoning has_many :salt_sugars)ならば
中間テーブルを作成する必要があります。

投稿2020/12/05 17:50

neko_daisuki

総合スコア2090

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

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

退会済みユーザー

退会済みユーザー

2020/12/06 00:54

neko_daisukiさん こんなにも早く具体的な解説までしていただけたことに感激です ありがとうございます 教えていただいた書き方の意味も調べながら、後者の複数紐づける方向でやってみて、改めてご報告いたします
退会済みユーザー

退会済みユーザー

2020/12/06 10:53

neko_daisukiさん 配列を許可するpermitの書き方勉強になりました。ありがとうございます。 実際にやってみて仰ったように配列では保存できないことを学べました。 中間テーブル作成ではカラムをbigint型にしてくださいというエラーが起きマイグレーションを失敗してしまいます。 下記を参考にいくつか修正を試してみました。 [referencesを使用した外部キー設定で沼った](https://qiita.com/Jwataru/items/7b840be38d4279224245) [作成されたテーブルにFK制約を張れない問題の解決策](https://qiita.com/nametaketakewo/items/d9d26fb301a09d7e6c2c) `ターミナルエラー表示` ``` -- create_table(:seasoning_salt_sugars) rails aborted! StandardError: An error has occurred, all later migrations canceled: Column `seasoning_id` on table `seasoning_salt_sugars` does not match column `id` on `seasonings`, which has type `bigint(20)`. To resolve this issue, change the type of the `seasoning_id` column on `seasoning_salt_sugars` to be :bigint. (For example `t.bigint :seasoning_id`). Original message: Mysql2::Error: Cannot add foreign key constraint ``` 試したこと - ターミナルの提案通り中間テーブルカラムをbigint型にし、外部キー制約はdef change外に記述しました ```ruby class CreateSeasoningSaltSugars < ActiveRecord::Migration[6.0] def change create_table :seasoning_salt_sugars do |t| t.bigint :seasoning_id t.bigint :salt_sugar_id t.timestamps end add_foreign_key :seasonings, :salt_sugars end end ``` - 以上でも同じエラーのため、  t.references :seasoning, type: :bigint, foreign_key: true  t.references :salt_sugar, type: :bigint, foreign_key: true にしても変わらなかったです。 - seasoningテーブルのsugar_salt_idカラムを  t.bigint :salt_sugar_idに修正もしてみました。 salt_sugar_idはActiveHashを用いてテーブルを作っておらず、seasoningテーブルのカラムとして存在している状態でも中間テーブルを作成することは可能でしょうか。salt_sugar_id以外にも調味料分類用に13種類ActiveHashでモデルを作成しております。 ActiveHashで種類別カテゴリーを作るのを諦めて、(何十個にもなる膨大なカラム数になってでも)seasoningテーブルのカラムに白砂糖、黒糖、きび砂糖・・・赤味噌、白味噌、合わせ味噌・・・作るようにしたり、 または塩_砂糖テーブル、味噌テーブル・・・とカテゴリ別にテーブルを作って全てにseasoningテーブルとの中間テーブルを作成したりしたほうがよいのでしょうか…
neko_daisuki

2020/12/06 11:46

ActiveHashを使っているのでsalt_sugar_id には外部キー制約がつけられないと思います。 t.references :seasoning, foreign_key: true t.references :salt_sugar これは通らないでしょうか?
退会済みユーザー

退会済みユーザー

2020/12/06 13:26

迅速なご対応ありがとうございます! ご提示いただいた形でマイグレーション無事通りました! 検証不足にも関わらず見当違いなことまで考えてしまいお恥ずかしい限りです。 設計からやり直しかと焦って視野が狭くなっていたところ、ActiveHashに中間テーブルを使えることを知れてよかったです…! ここからまた自身でアソシエーションやビューへの反映等を実践してみて、教えていただいた書き方と中間テーブルへの理解を深めたいと思います。 neko_daisukiさん改めて、ありがとうございます!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問