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

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

ただいまの
回答率

88.81%

paramsのネストされた値がストロングパラメータで取得できない

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 5,163

ruby_0ct

score 53

paramsからストロングパラメータを通して値を取得したいのですが、newを行った時にnilとなってしまい、ネストされた要素の値が取得できません。

商品登録を行う処理でhas_manyincludesさせた商品カテゴリーテーブルをネストしています。

カテゴリーはプルダウンメニューで選択するのですが、そのvalue(テーブルでいうところのid)が取得できません。
ストロングパラメータの書き方を色々変えてもできず、どのようにしたら、ストロングパラメータを通して取得できるのでしょうか?それとも、別の取得方法をするのでしょうか?
教えていただければ助かります。

テーブルの関係は、
productcategory 1対多 product

paramsの中身

Parameters: {
  "utf8"=>"✓", 
  "authenticity_token"=>"", 
  "product"=>{
     "product_name"=>"商品名",
     "productcategories"=>{
         "productcategory_id"=>"2"
     }
  },
 "commit"=>"商品を追加する"
}


取得できない要素は、カテゴリーテーブルのproductcategory_idです。

product_controller.rb

def product_params
      product_params = params.require(:product).permit(:id, :product_name, productcategories: [:productcategory_id])
end

 モデル

product.rb

class Product < ApplicationRecord
  has_many :productcategories
  validates_associated :productcategories
  accepts_nested_attributes_for :productcategories
end


productcategory.rb

class Productcategory < ApplicationRecord
  belongs_to :poduct
  accepts_nested_attributes_for :product
end

 コントローラ

def new
    @product = Product.new
    @category = Productcategory.new
end

def create
    @product = Product.new(product_params)

    respond_to do |format|
      if @product.save!
        format.html { redirect_to @product, notice: '商品の追加完了' }
        format.json { render :show, status: :created, location: @product }
      else
        format.html { redirect_to new_product_url }
        format.json { render json: @product.errors, status: :unprocessable_entity }
      end
    end
end

private
def product_params
      product_params = params.require(:product).permit(:productname, productcategories: [:productcategory_id])
end

@productをデバッグしてみると

<Product id: 5, productname: "商品名A", productcategory_id: nil>


nilとなって取得できていません。

 view

カテゴリーはプルダウンメニューから選びます。

products/new.html.erb

<%= form_for @product do |f| %>
    <p><%= f.text_field :productname, placeholder: '商品名を入力', autocomplete: 'off' %></p>

    <%= f.fields_for :productcategories do |c|  %>
        <p><%= c.collection_select :productcategory_id, Productcategory.all, :id, :category, prompt: 'カテゴリーを選択' %></p>
    <% end %>

    <div class="formsubmit"><%= f.submit '商品を追加する' %></div>
<% end %>
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

check解決した方法

0

一から作り直しを行ったところ、解決しました。
modelの設定など細かいところで誤りがあったことが、原因でした。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

params.require(:product).permit(:id, :product_name, productcategories: [:productcategory_id])

で合っていると思います。

rails console で以下のように実験して確かめました。

p1 = ActionController::Parameters.new(
  {
    "utf8"=>"✓",
    "authenticity_token"=>"",
    "product"=>{
       "product_name"=>"商品名",
       "productcategories"=>{
           "productcategory_id"=>"2"
       }
    },
   "commit"=>"商品を追加する"
  }
)

p2 = p1.require(:product).permit(:id, :product_name, productcategories: [:productcategory_id])

puts p2[:productcategories][:productcategory_id]
# => 2

期待通り 2 が得られました。
なぜ「取得できない」と思われたのでしょうか。

ところで,

def product_params
      product_params = params.require(:product).permit(:id, :product_name, productcategories: [:productcategory_id])
end

の product_params = は不要です。
このローカル変数のスコープはメソッド内なのでよそで使われる可能性はありません。代入する意味が無いのです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/03/29 03:35 編集

    素早すぎるご回答ありがとうございます。
    う〜ん、不思議です。
    params[:product][:productcategories][:productcategory_id]だと取得できるのですが、

    @product = Product.new(product_params)をした後にputs(@book.inspect)で確認してみると、
    productcategory_idがnilとなっています。

    ストロングパラメータに原因があるとしか思えなかったのですが..
    [上のコメント修正 03:40]paramsではなく、ストロングパラメータです。

    product_params = に関してもありがとうございます。
    scaffoldで自動で生成されたので、そのままにしていました。

    キャンセル

  • 2018/03/29 03:51

    puts(@book.inspect) じゃなくて puts(@product.inspect) ですよね?
    ちなみにこれは p @product と書けます。(p メソッドは平たく言うと inspect したやつを表示します)

    いろいろ間違っています。
    一つの Productcategory に複数の Product があり,一つの Product は一つの Productcategory に属すのですよね?
    であれば,とりあえず,
    Product モデルは
    belongs_to :productcategory
    でなければならないし,
    Productcateogry モデルは
    has_many :product
    でなければなりません。あべこべです。

    キャンセル

  • 2018/03/29 03:52

    scaffold で product_params = が付くのはありそうにないですが。

    キャンセル

  • 2018/03/30 02:19

    色々混乱しておりました。
    @productで合ってます。

    has_manyとbelongs_toを修正しました。そうすると、プルダウンメニューが表示されなくなったため、
    <%= f.fields_for(@product) do |c| %>に変更し、コントローラのnewアクションには
    @book.build_bookcategoryを追加しました。

    そうすると、paramsのネスト部分が、productcategoryではなくproductに変わりました。
    Parameters: {"product"=>{"product"=>{"productcategory_id"=>"2"}}

    ストロングパラメータもproductに変更しましが、相変わらずnilとなっています。

    キャンセル

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

  • ただいまの回答率 88.81%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る