ピグミー奮闘記。プログラミングと趣味の日記。

プログラミングと趣味についてあれこれ思考を記録するブログ!

初めてのWebアプリ開発:4日目

はじめてのオリジナルWebアプリ開発を始めて4日目の記録。
現在レシピ投稿アプリを開発しています。

今日学んだことまとめ

ネストした子モデルのparamsを親モデルのコントローラーで受け取り、保存する方法。

Model
class Recipe < ApplicationRecord
  belongs_to :user

  has_many :ingredients, dependent: :destroy
  has_many :instractions, dependent: :destroy

  accepts_nested_attributes_for :ingredients, allow_destroy: true
  accepts_nested_attributes_for :instractions, allow_destroy: true
end
class Ingredient < ApplicationRecord
  belongs_to :recipe
end
class Instraction < ApplicationRecord
  belongs_to :recipe
end
View
  <%= form_for(recipe) do |f| %>
     #(フォーム内容)
  <% end %>
</div>
     #今回はフォームで入力フィールドを増減できるよう「nested_form_fields」のgem使用
Controller
def new
    @recipe = current_user.recipes.build   
    #recipeモデルのインスタンス生成 .buildは保存はせず生成のみ
    @recipe.ingredients.build  
    #recipeモデルに関連づいたingredientモデルのインスタンス生成
    @recipe.instractions.build  
    #recipeモデルに関連づいたinstractionモデルのインスタンス生成
  end

  def create
    @recipe = current_user.recipes.build(recipe_params) 
    #@recipeの引数にフォームから受けとるrecipe_paramsを渡す。
    if @recipe.save    #ここで保存。
      flash[:success] = 'レシピを投稿しました。'
      redirect_to current_user
    else
      flash[:danger] = 'レシピの投稿に失敗しました。'
      render :new
    end
  end


private
  
  def recipe_params 
    #親モデル(recipes)のコントローラーでネストされた子モデル(ingredients,instractions)のparamsも合わせて取得する
    params.require(:recipe).permit(
      :title, :content, :volume, 
      ingredients_attributes: [:name, :amount, :_destroy], 
      instractions_attributes: [:content, :_destroy]
      )
  end

レシピ一覧ページでは概要(タイトルとおすすめ文)だけ表示し、レシピ詳細ボタンを押すと詳しいレシピを表示するようにしました。
この概要ページから詳細ページへ引数を渡すところでエラー文が出て、渡すべきパラメーターについて理解が曖昧だったことに気づき、link_toメソッドの勉強になったので記録。

<% recipes.each do |recipe| %> 
      #recipesから一つずつrecipeオブジェクトを取り出し変数recipeに代入していく
  <%= recipe.title %>
      <% user = recipe.user %> 
      <%= link_to user.name, user_path(user), class: 'text-left' %><span class="text-muted pull-right"><%= l recipe.created_at, format: :short %></span> 
      #user_path(user)では引数としてuserオブジェクトを指定。つまりeachメソッドによって取り出された個別のuserモデルオブジェクト、つまりuser.idがリンク先のパスに指定される。users#showに対するパスであるuser_path(user)で生成されるパスは$rails routesで確認すると/users/:id/(.:format)なので、最終的に/users/2(user.id = 2の場合)のようなパスが生成される。
                     #(途中省略)
    <%= link_to 'レシピ詳細', recipe_path(recipe, user_id: user.id) %> 
                     #recipe(Recipeモデルのオブジェクト)を引数で渡す。
                     #これはrecipe_path()で生成されるパスを$rails routesで確認するとわかる。
                     #生成されるパスは/recipes/:id/(.:format)でありrecipe.idが渡される必要がある。
<% end %>

エラー文から、ルーティングをいじったため生成されるパスが変わったことにより、渡すべき引数が変わってしまったことが原因であると判断。

これをレシピコントローラーのprivate下のparamsで受け取ります。

recipes_controller
 class RecipesController < ApplicationController
   before_action :recipe_params_show, only: [:show]
 
   def show
   end

   private

   def recipe_params_show
     @recipe = Recipes.find_by(id: params[:id])
   end
end


今日はこんな感じで色々と勉強になりました。ここはこうした方がいいよ、とかここは間違っているよ、などのご指摘があればぜひ教えていただけると有難い限りです!

現在主に、「Ruby on Rails 5 アプリケーションプログラミング」の書籍をメインに勉強しています。
疑問が出たらまずはこの本で調べます。特に複数データベースのアソシエーションについては度々参照しています。
この本に乗っていない場合はググるかQuiitaやStackOverflowなどで調べています。StackOverflowでは英語の記事数が日本語のそれに比べ圧倒的に多いため、英語の記事もよく参照しています。

Ruby on Rails 5アプリケーションプログラミング

Ruby on Rails 5アプリケーションプログラミング

Ruby on Rails 5 アプリケーションプログラミング」の前に参考にしていたのはこちらの書籍です。初心者にとっても親切丁寧に解説されており、上の書籍に進む前の段階で大変お世話になりました。

Ruby on Rails 5 超入門

Ruby on Rails 5 超入門

他にも購入したい書籍が山積みですが、地道に一歩づつ。

4月後半から始めたプログラミング、まだまだ先は長いですが頑張りたいと思います。