RailsTutorial14章

index

    add_index :relationships, :follower_id
    add_index :relationships, :followed_id
    add_index :relationships, [:follower_id, :followed_id], unique: true

高速化のため。 add_index :relationships, [:follower_id, :followed_id], unique: true 2つを揃って検索することが考えられるためこのような記法になる。

モデルについて

app/models/user.rb

class User < ApplicationRecord
  has_many :microposts, dependent: :destroy
  has_many :active_relationships, class_name:  "Relationship",
                                  foreign_key: "follower_id",
                                  dependent:   :destroy
  .
  .
  .
end

microposts

デフォルトだと class_name: "Micropost"

        foreign_key: "user_id" 自明だったので書かなかった。

=> "#{Model Name}s"が規約

規約に則っていないから追加している。 active_relationships このままだとactive_relashionship model (class)を探しに行っちゃうのでRelationshipを指定する このままだとUsetrモデルを探しにいく?のでfollow_idだと分からせる。 has_manyはたくさんのメソッドを生成する。そのときに使用するのはRelationshipを使ってね

UserのidとRelationshipテーブルのfollower_id が紐付いている

app/models/relationship.rb

class Relationship < ApplicationRecord
  belongs_to :follower, class_name: "User"
  belongs_to :followed, class_name: "User"
end

class_nameをつけないと"#{Model Name}s"が規約 Follwer_id, Follwerクラスを探しに行ってしまうから

Relationshipテーブルのfollower_idとUserのidが紐付いている Relationshipテーブルのfollowed_idとUserのidが紐付いている

belongs_to, has_manyはメソッドを生成するメソッド

has_many throughについて

f:id:shiness:20210118162530p:plain

Userに紐付いたrelationshipのidが欲しいわけではなく user.followingが欲しいという動機

@user.active_relationships.map(&:followed) 上でも呼び出せるけどめんどくさいからメソッドを作ろうよという流れ

has_many :following, through: :active_relationships, source: :followed

followingメソッド

Userクラスのインスタンスに対して active_relationshipsメソッドを実行し、それで得られたそれぞれのRelationshipテーブル のインスタンスに対してfollowedメソッドを実行したものを返してくれるもの

便利クラス

  def follow(other_user)
    following << other_user
  end

  # ユーザーをフォロー解除する
  def unfollow(other_user)
    active_relationships.find_by(followed_id: other_user.id).destroy
  end

  # 現在のユーザーがフォローしてたらtrueを返す
  def following?(other_user)
    following.include?(other_user)
  end

f:id:shiness:20210118164632p:plain

f:id:shiness:20210118192056p:plain

共通のパーシャル

JavascriptによるAjaxの実装

f:id:shiness:20210118203152p:plain

RailsTutorial13章

複合キーインデックス

add_index :microposts, [:user_id, :created_at]

newではなくbuildで書くとアソシエーションベースでインスタンス生成している ことを明示することになる。

proc

default_scope -> { order(created_at: :desc) }
>> -> { puts "foo" }
=> #<Proc:0x007fab938d0108@(irb):1 (lambda)>
>> -> { puts "foo" }.call
foo
=> nil

f:id:shiness:20210117231514p:plainf:id:shiness:20210118014507p:plain

render記法

<ol class="microposts">
  <%= render @microposts %>
</ol>

パーシャルを使って自動的に@users変数内のそれぞれのユーザーを出力していました。これを参考に、>_micropost.html.erbパーシャルを使ってマイクロポストのコレクションを表示しようとすると、次のよ>うになります。

<%= will_paginate %>

実は、上のコードは引数なしで動作していました。これはwill_paginateが、Usersコントローラのコンテ>キストにおいて、@usersインスタンス変数が存在していることを前提としているためです。このインスタンス変数は、10.3.3でも述べたようにActiveRecord::Relationクラスのインスタンスです。今回の場合 はUsersコントローラのコンテキストからマイクロポストをページネーションしたいため(つまりコン テキストが異なるため)、明示的に@microposts変数をwill_paginateに渡す必要があります。したがっ て、そのようなインスタンス変数をUsersコントローラのshowアクションで定義しなければなりません (リスト 13.23)。

f:id:shiness:20210117235329p:plain

f.object

f.objectについて

app/views/shared/_micropost_form.html.erb

<%= form_with(model: @micropost, local: true) do |f| %>
  <%= render 'shared/error_messages', object: f.object %>
  <div class="field">
    <%= f.text_area :content, placeholder: "Compose new micropost..." %>
  </div>
  <%= f.submit "Post", class: "btn btn-primary" %>
<% end %>

sharedでuserとmicropostsで切り替えてくれたら嬉しい。 renderのあとでパーシャルの先で渡した(変数なんでもよい)をローカル変数として呼び出せる <%= render 'shared/error_messages', object: f.object %>

コードリーディング

@micropost = current_user.microposts.find_by(id: params[:id])

    def correct_user
      @micropost = current_user.microposts.find_by(id: params[:id])
      redirect_to root_url if @micropost.nil?
    end

 コードリーディング

redirect_to request.referrer || root_url

ここではrequest.referrerというメソッドを使っています14 。このメソッドはフレンドリーフォワーデ>ィングのrequest.url変数(10.2.3)と似ていて、一つ前のURLを返します(今回の場合、Homeページ: になります)15 。このため、マイクロポストがHomeページから削除された場合でもプロフィールペ ージから削除された場合でも、request.referrerを使うことでDELETEリクエストが発行されたページ に戻すことができるので、非常に便利です。ちなみに、元に戻すURLが見つからなかった場合でも (例えばテストではnilが返ってくることもあります)、リスト 13.53の||演算子でroot_urlをデフォル トに設定しているため、大丈夫です。(リスト 9.24で定義したデフォルトオプションと比較してみてください。)

RailsTutorial12章

複合キーインデックス

add_index :microposts, [:user_id, :created_at]

newではなくbuildで書くとアソシエーションベースでインスタンス生成している ことを明示することになる。

proc

default_scope -> { order(created_at: :desc) }
>> -> { puts "foo" }
=> #<Proc:0x007fab938d0108@(irb):1 (lambda)>
>> -> { puts "foo" }.call
foo
=> nil

f:id:shiness:20210117231514p:plainf:id:shiness:20210117231514p:plain

render記法

<ol class="microposts">
  <%= render @microposts %>
</ol>

パーシャルを使って自動的に@users変数内のそれぞれのユーザーを出力していました。これを参考に、>_micropost.html.erbパーシャルを使ってマイクロポストのコレクションを表示しようとすると、次のよ>うになります。

<%= will_paginate %>

実は、上のコードは引数なしで動作していました。これはwill_paginateが、Usersコントローラのコンテ>キストにおいて、@usersインスタンス変数が存在していることを前提としているためです。このインス>タンス変数は、10.3.3でも述べたようにActiveRecord::Relationクラスのインスタンスです。今回の場合 はUsersコントローラのコンテキストからマイクロポストをページネーションしたいため(つまりコン テキストが異なるため)、明示的に@microposts変数をwill_paginateに渡す必要があります。したがっ て、そのようなインスタンス変数をUsersコントローラのshowアクションで定義しなければなりません (リスト 13.23)。

f:id:shiness:20210117235329p:plain

f.object

f.objectについて

app/views/shared/_micropost_form.html.erb

<%= form_with(model: @micropost, local: true) do |f| %>
  <%= render 'shared/error_messages', object: f.object %>
  <div class="field">
    <%= f.text_area :content, placeholder: "Compose new micropost..." %>
  </div>
  <%= f.submit "Post", class: "btn btn-primary" %>
<% end %>

sharedでuserとmicropostsで切り替えてくれたら嬉しい。 renderのあとでパーシャルの先で渡した(変数なんでもよい)をローカル変数として呼び出せる <%= render 'shared/error_messages', object: f.object %>

コードリーディング

@micropost = current_user.microposts.find_by(id: params[:id])

    def correct_user
      @micropost = current_user.microposts.find_by(id: params[:id])
      redirect_to root_url if @micropost.nil?
    end

 コードリーディング

redirect_to request.referrer || root_url

ここではrequest.referrerというメソッドを使っています14 。このメソッドはフレンドリーフォワーデ>ィングのrequest.url変数(10.2.3)と似ていて、一つ前のURLを返します(今回の場合、Homeページ: になります)15 。このため、マイクロポストがHomeページから削除された場合でもプロフィールペ ージから削除された場合でも、request.referrerを使うことでDELETEリクエストが発行されたページ に戻すことができるので、非常に便利です。ちなみに、元に戻すURLが見つからなかった場合でも (例えばテストではnilが返ってくることもあります)、リスト 13.53の||演算子でroot_urlをデフォル トに設定しているため、大丈夫です。(リスト 9.24で定義したデフォルトオプションと比較してみて>ください。)

RailsTutorial12章

複合キーインデックス

add_index :microposts, [:user_id, :created_at]

newではなくbuildで書くとアソシエーションベースでインスタンス生成している ことを明示することになる。

proc

```` default_scope -> { order(created_at: :desc) }




-> { puts "foo" } => #<Proc:0x007fab938d0108@(irb):1 (lambda)> -> { puts "foo" }.call foo => nil

[f:id:shiness:20210117231514p:plain][f:id:shiness:20210117231514p:plain]

#render記法
    <%= render @microposts %>
>パーシャルを使って自動的に@users変数内のそれぞれのユーザーを出力していました。これを参考に、>_micropost.html.erbパーシャルを使ってマイクロポストのコレクションを表示しようとすると、次のよ>うになります。


<%= will_paginate %>

>実は、上のコードは引数なしで動作していました。これはwill_paginateが、Usersコントローラのコンテ>キストにおいて、@usersインスタンス変数が存在していることを前提としているためです。このインス>タンス変数は、10.3.3でも述べたようにActiveRecord::Relationクラスのインスタンスです。今回の場合
>はUsersコントローラのコンテキストからマイクロポストをページネーションしたいため(つまりコン
>テキストが異なるため)、明示的に@microposts変数をwill_paginateに渡す必要があります。したがっ
>て、そのようなインスタンス変数をUsersコントローラのshowアクションで定義しなければなりません
>(リスト 13.23)。


[f:id:shiness:20210117235329p:plain]


# f.object

`f.object`について

app/views/shared/_micropost_form.html.erb

<%= form_with(model: @micropost, local: true) do |f| %> <%= render 'shared/error_messages', object: f.object %>

<%= f.text_area :content, placeholder: "Compose new micropost..." %>
<%= f.submit "Post", class: "btn btn-primary" %> <% end %>

sharedでuserとmicropostsで切り替えてくれたら嬉しい。
renderのあとでパーシャルの先で渡した(変数なんでもよい)をローカル変数として呼び出せる
`  <%= render 'shared/error_messages', object: f.object %>`


# コードリーディング

` @micropost = current_user.microposts.find_by(id: params[:id])`


def correct_user
  @micropost = current_user.microposts.find_by(id: params[:id])
  redirect_to root_url if @micropost.nil?
end
# コードリーディング

redirect_to request.referrer || root_url


>ここではrequest.referrerというメソッドを使っています14 。このメソッドはフレンドリーフォワーデ>ィングのrequest.url変数(10.2.3)と似ていて、一つ前のURLを返します(今回の場合、Homeページ:
>になります)15 。このため、マイクロポストがHomeページから削除された場合でもプロフィールペ
>ージから削除された場合でも、request.referrerを使うことでDELETEリクエストが発行されたページ
>に戻すことができるので、非常に便利です。ちなみに、元に戻すURLが見つからなかった場合でも
>(例えばテストではnilが返ってくることもあります)、リスト 13.53の||演算子でroot_urlをデフォル
>トに設定しているため、大丈夫です。(リスト 9.24で定義したデフォルトオプションと比較してみて>ください。)

Rubyの復習

紹介

yieldについて

application.html.erb

<!DOCTYPE html>
<html>
  <head>
    <title>MessageBoard</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <%= yield %>
  </body>
</html>

index.html.erb や show.html.erb などの各ページが入る。

<Message::ActiveRecord_Relation:0x00007ffac5a15f78>

viewに@messagesをこのように渡した場合の挙動

  def index
    @messages = Message.all
<ul>
  <%= @messages %>
</ul>

保存が失敗したときには messages/new.html.erb を表示するように指定しています。 @message = Message.new(message_params) によって @message インスタンスは残っており @message.content には値が入っているので、 new.html.erb 内のフォームにある form_for(@message) 内の content の入力欄にはたった今失敗した文字列値が予め入力された状態になる。

flash[:success] = 'Message が正常に投稿されました' は、 @message.save が成功したときに実行される。 flash はハッシュなので、 { success: 'Message が正常に投稿されました' } という形で保存される。 これが Controller (MessagesController) から View (app/views/layouts/_flash_messages.html.erb) へ受け渡され、表示される。

<% flash.each do |message_type, message| %>
  <div><%= message %></div>
<% end %>

上記は、flash に代入された全てのメッセージが1つ1つ取り出されて、全て表示される。 ハッシュであるため、 each で取り出すと、 |key, value| のペアで取り出される。 今回は |message_type, message| という変数名を用いている。 @message.save が成功した場合、 message_type には :success が代入され、message に 'Message が正常に投稿されました' が代入され、message のみ表示される。

  def destroy
    @message = Message.find(params[:id])
    @message.destroy

    flash[:success] = 'Message は正常に削除されました'
    redirect_to messages_url
  end

今まではprefix_path だがリダイレクトの場合だけは prefix_url を使用する。

f:id:shiness:20210117160120p:plainf:id:shiness:20210117160133p:plain

Prefix + _path となっている。 :id が必要なものはインスタンスを特定する必要があるので引数として @message などのインスタンスが必要。 今後もこの法則で自動生成されるメソッド(prefix_path)を使って、リンクを生成する。

link_to redirect_to

【Rails】link_toの使い方をマスターして簡単にリンクを作成し | Pikawaka - ピカ1わかりやすいプログラミング用語サイト

Rails復習

なぜオブジェクト指向が必要か?などRubyから入った人全員にオススメだと思う書籍

Javaで書かれていますがここ数年で1番素晴らしい本だと思いました。 Rubyの入門本は分かってる前提で書かれていることが よくわかりました。何度も復習したいと思います。 Javaもやってみたいですね。

MVCモデル

f:id:shiness:20210116131952p:plain

  • URLとHTTPメソッドを受け取って Controller に渡すのが、Router
  • リソース(データ)として振る舞うのが、Model
  • Model を表示・整形する雛形がView
  • Model や View を制御するのが、Controller

開発の流れ

1.Model

2.Router

3.ルーティング毎に

4.Controller

5.View

f:id:shiness:20210116133503p:plain

Router に書かれた1つのルーティングが、複数の Controller の1つのメソッド(アクション)に相当し、 Controller の1つのメソッド(アクション)が1つの View ファイルに対応する。

redirect_to と render の違い

redirect_to 処理を アクションへと強制的に移動させるもので、 アクションが実行されhtml.erb が呼ばれます。renderはhtml.erb を表示するだけ(アクションは実行しない)。

flashflash.now の違い

いつ使用するかの基準としては、 redirect_to の前なら flash であり、render の前なら flash.now です。 理由は、redirect_to は、HTTP リクエストを発生させるので flash.now だと内容を保持できずに消えてしまうし、 render は HTTP リクエストを発生させないので flash.now が消えないから。

Railsの立ち位置

f:id:shiness:20210116140750p:plain

RailsTutorial12章

参考

パスワード再設定

f:id:shiness:20210115171806p:plain

f:id:shiness:20210115171849p:plain

本人認証されているメールアドレスに送ることが大前提 f:id:shiness:20210115172059p:plain

f:id:shiness:20210115172234p:plain

email情報が渡されてくる。 emailを小文字にしておく!ユーザいますか?チェック

  def create
    @user = User.find_by(email: params[:password_reset][:email].downcase)
    if @user
      @user.create_reset_digest
      @user.send_password_reset_email

selfはユーザオブジェクト。呼び出しているあなたを引数を渡してね

  def send_password_reset_email
    UserMailer.password_reset(self).deliver_now
  end

データの流れ

  1. @user.send_reset_email
  2. UserMailer.password_reset(self).deliver_now
 3. def password_reset(user)
 4.  @user = user
    mail to: user.email, subject: "Password reset"
  end

activatonのところの処理を2つに分けたイメージ editアクションを呼び出したときにチェックして 最終的にうまくいったら実行する。 だめだったらリダイレクトする。

 before_action :get_user,   only: [:edit, :update]
 before_action :valid_user, only: [:edit, :update]
 
   def get_user
      @user = User.find_by(email: params[:email])
    end

    # 正しいユーザーかどうか確認する
    def valid_user
      unless (@user && @user.activated? &&
              @user.authenticated?(:reset, params[:id]))
        redirect_to root_url
      end
    end

パスワード更新の3つの条件

f:id:shiness:20210115180926p:plain

hidden_tagについて

実際にe_mail入力させない

ただし、今回の作業は少しだけ面倒な点があります。というのも、メールアドレスをキーとしてユーザーを検索するためには、editアクションとupdateアク>ションの両方でメールアドレスが必要になるからです。例のメールアドレス入りリンクのおかげで、editアクションでメールアドレスを取り出すことは問題>ありません。しかしフォームを一度送信してしまうと、この情報は消えてしまいます。この値はどこに保持しておくのがよいのでしょうか。今回はこのメー>ルアドレスを保持するため、隠しフィールドとしてページ内に保存する手法をとります。

edit,upadateでも@userが必要だし(get_user)正しいユーザ(valid_user)か見分ける必要がある。 get_userではemailが必要になるのでhidden_fieldが必要になる。

hidden_fieldについて

[参考] qiita.com