NoMethodError in _Controller #_ private method `_' called for の原因について
状況
Userクラスのtestメソッドを呼び出したときにこのエラーに遭遇
class User < ApplicationRecord ... end def test ... end
原因
endの位置がおかしかった
以下のように修正することで解決!
class User < ApplicationRecord ... def test ... end end
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について
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
共通のパーシャル
JavascriptによるAjaxの実装
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
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.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
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.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 %>
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の復習
紹介
- 作者:中山 清喬,国本 大悟,株式会社フレアリンク
- 発売日: 2019/11/15
- メディア: Kindle版
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 を使用する。
Prefix + _path となっている。 :id が必要なものはインスタンスを特定する必要があるので引数として @message などのインスタンスが必要。 今後もこの法則で自動生成されるメソッド(prefix_path)を使って、リンクを生成する。
link_to redirect_to
【Rails】link_toの使い方をマスターして簡単にリンクを作成し | Pikawaka - ピカ1わかりやすいプログラミング用語サイト
Rails復習
なぜオブジェクト指向が必要か?などRuby
から入った人全員にオススメだと思う書籍
- 作者:中山 清喬,国本 大悟,株式会社フレアリンク
- 発売日: 2019/11/15
- メディア: Kindle版
Java
で書かれていますがここ数年で1番素晴らしい本だと思いました。
Ruby
の入門本は分かってる前提で書かれていることが
よくわかりました。何度も復習したいと思います。
Java
もやってみたいですね。
MVCモデル
- URLとHTTPメソッドを受け取って Controller に渡すのが、Router
- リソース(データ)として振る舞うのが、Model
- Model を表示・整形する雛形がView
- Model や View を制御するのが、Controller
開発の流れ
1.Model
2.Router
3.ルーティング毎に
4.Controller
5.View
Router に書かれた1つのルーティングが、複数の Controller の1つのメソッド(アクション)に相当し、 Controller の1つのメソッド(アクション)が1つの View ファイルに対応する。
redirect_to と render の違い
redirect_to 処理を アクションへと強制的に移動させるもので、 アクションが実行されhtml.erb が呼ばれます。renderはhtml.erb を表示するだけ(アクションは実行しない)。
flash と flash.now の違い
いつ使用するかの基準としては、 redirect_to の前なら flash であり、render の前なら flash.now です。 理由は、redirect_to は、HTTP リクエストを発生させるので flash.now だと内容を保持できずに消えてしまうし、 render は HTTP リクエストを発生させないので flash.now が消えないから。
Railsの立ち位置