- 投稿日:2020-02-25T23:53:59+09:00
Sequel Proへのデータベース作成
rails db:createで、データベースを作成できる。
VS Codeでdatabase.ymlを見ると運用環境が記述されており、
development、test、productionとある。
developmentは通常、開発をする際に使用する環境。
testはテスト環境。アプリケーションの動作をテストする際に使用する環境。
productionは本番環境。アプリケーションを実際にリリースする際に使用する環境。
rails db:createをターミナルに記述するとSequel Pro(シークエル・プロ)にアプリケーション名developmentとアプリケーション名testが作られる。
- 投稿日:2020-02-25T23:40:49+09:00
Railsの復習
はじめに
標題の通りRailsの復習です。
部分テンプレート
Webアプリケーションにて、各ページに共通する箇所を切り出して1つのファイルにまとめたもの。ファイル名の先頭には「」が付く。ビュー側では部分テンプレートを呼び出しているにも関わらず、部分テンプレートのファイル名に「」が付いていないとエラーになります。実装時にはERBファイルに以下のように書きます。
<%= render partial: "使用する部分テンプレート", locals: {部分テンプレート中の変数: 部分テンプレートで使いたい値} %>わかりづらいと思うので、実例を示します。
<%= render partial: "hoge", locals: {fuga: "test"} %>これで「_hoge.html.erb」という部分テンプレートで"test"という文字列が入った変数”fuga”が使えます。
アソシエーション
モデル間で紐付けを行うことです。ツイッターを例にすると、ユーザー情報を格納するUsersテーブルとツイートを格納するTweetsテーブルがあったとします。どのユーザーがどのツイートをしたのか紐付けを行わなければアプリケーションとして破綻しますので、アソシエーションが必要になってきます。実装時にはモデルにテーブル間の関係を記載します。
・ユーザーモデルの場合
Class User 中略 has_many :tweets end1人のユーザーに対してツイートは0個以上存在するため「has_many :tweets」となります。
・ツイートモデルの場合
Class Tweet 中略 belongs_to :Users end1つのツイートに対して紐づくユーザーは必ず一人になります。そのため、「belongs_to :Users」となります。
バリデーション
データの登録に制限をかけることです。先ほどと同じようにツイッターを例にあげると、ツイート欄が空白のままでは投稿しても意味がありません。なので、ツイート欄が空白の場合はデータベースに登録させないように制限をかけます。これがバリデーションです。モデルに以下のような記述を加えれば実装できます!
class Tweet < ApplicationRecord validates :tweet, presence: true end1つずつ解説。
・validates ApplicationRecordクラスのメソッドらしいです。ApplicationRecordクラスを継承しているためTweetクラスでも使える。
・:tweet クライアントから送られてきたツイートが入っています。
・presence: true 入力値が空でないことを確認します。空でなければバリデーションチェックを通過してDBにデータが登録されます!まとめ
私の頭の中でモヤモヤしていたものをまとめました。某スクールの某試験でカンペに使えるかもしれません。
- 投稿日:2020-02-25T23:36:52+09:00
初めてのチーム開発(フリマサイト)その2
- 投稿日:2020-02-25T22:08:13+09:00
Rails & JS系(Vueとか)のフレームワークで未来の時間のテストをする方法
Rails側(サーバサイド)
Timecopを導入。
とりあえずGemfileに1行挿入。Gemfile(前略) group :development, :test do (中略) gem 'timecop' #この一行をdevelopmentとかstagingの中に書く (後略) endStaging環境の場合は、当然staging.rbに記述してください。
config/environments/development.rbRails.application.configure do (中略) config.after_initialize do t = Time.local(2023, 3, 25, 10, 5, 0) # 2023年3月25日10時5分0秒に固定 Timecop.travel(t) end endJS側(クライアントサイド)
力技。OSの時間設定をいじれ!
取り敢えずMacだとシステム環境設定から。
こんな時に便利
予定されたリリースをシミュレートしたり、月初の処理が適切に行われているか等の確認に使える。
翌月にならないとテストできない、リリース当日のぶっつけ本番は避けたいですよね。
- 投稿日:2020-02-25T21:48:57+09:00
ActiveRecord::RecordNotFound in
今回ActiveRecord::RecordNotFound inのエラーで困ったのでメモです。
teratailで結果的に教えて頂き解決したのですがメモとして忘れないように書きたいと思います。
ほぼ質問した事のコピーとその続きです。テーブル名 ・novel_lists ・users 多(novel_losts):1(users)の関係です。 novel_listsには ・title ・genre ・novel_keyword ・synopsis ・user_id 以上の5つのカラムがあります。今回はusersのshow.html.erbファイルに書いていきます。
<% @novel_list.each do |novel_list| %> <div class="novellist_toptable"> <tbody> <tr> <td><%= link_to novel_list.title, novel_list_path(novel_list) %></td> <td><%= novel_list.genre %></td> </tr> <tr> <td></td> </tr> </tbody> </table> </div> <% end %> このように記載し、novel_list_pathへとlinkをつなげています。 このlinkを踏んだ際に出るエラーとなります まずはusersコントローラのshowアクションの部分です。 class UsersController < ApplicationController def show @user = User.find(params[:id]) @novel_list = @user.novel_lists @followings = @user.followings.page(params[:page]) @novel_lists = NovelList.all @favposts = current_user.favposts.pageエラー内容
ActiveRecord::RecordNotFound in NovelListsController#show Couldn't find User with 'id'=4 Extracted source (around line #9): def show @user = User.find(params[:id])ここの部分にエラーが出ています。 @novel_list = NovelList.find(params[:id]) @novel_post = NovelPost.find(params[:id]) @novel_posts = @novel_list.novel_postsNovelListsControllerと出ているので・・・
novel_listsコントローラです。 class NovelListsController < ApplicationController def show @user = User.find(params[:id]) @novel_list = NovelList.find(params[:id]) @novel_post = NovelPost.find(params[:id]) @novel_posts = @novel_list.novel_posts end教えて頂いた解決策
エラー文に"Couldn't find User with 'id'=4"と書いてあります。意味としては、「id=4のユーザーはないよ」と言っています。なぜ、このようなことになっているかというと、novel_listsコントローラで@user = User.find(params[:id])としているからです。 今、id=4のノベルをクリックしているのでparams[:id]の値は4となります。なので、id=4のユーザーを探しに行った結果、id=4のユーザーは存在しないよと言っています。 そもそも、novel_listの中にユーザーidの情報が入っているので、そこでわざわざ@userとしなくていいと思います。Novel_listテーブルとUserテーブルをアソシエーションで結んでいれば、例えば、ビュー側で@novel_list.user.nameとすれば、ユーザーの情報は表示できると思います。今までコントローラに書いて取得できるものであれば問題なく表示できるという認識でやってましたがここでとても重要な事を教わりました。
上記とてもわかりやすく、@user = User.find(params[:id])としてた事で、探して欲しいものとは違うものを取得する為に
コンピュータが動いていたとは予想外・・・でした。https://teratail.com/questions/243317
こちら質問した際のURLです。内容はほぼ一緒です。
最後に@user削除後
作者:<%= link_to @novel_list.user.name, user_path(@novel_list) %> 作者の呼び出しに@user.nameを使ってたのエラーとなった訳ですが、 アドバイス通り、@novel_list.user.nameにする事で無事に呼び出す事が出来ました。わかりやすく教えて頂けて感謝ですね。
今回困ったメモは以上です。
- 投稿日:2020-02-25T20:15:16+09:00
link_toでカラムに値を代入する
link_toで飛ぶと同時にカラムに値を代入する様にするまでの方法をまとめます。
今回は飲食店の投稿サイトを例に使います。お店の詳細情報ページから、そのお店のレビューを投稿するためにlink_toを用いてshop_idをlink_toに持たせてレビューを投稿できる様にします。
使いたい値をlink_to内で飛ばす
show.html.erb... <%= link_to "お店について投稿する", new_post_path(:shop_id => @shop.id) %> ...お店の詳細ページでレビュー(postsモデル)が持つ
:shop_id
カラムにお店のid
カラムをlink_to内で代入します。こうすることで飛んだ先のpostsのnewページのurlは
localhost:3000/posts/new ?shop_id=1
という形になりparams[:shop_id]
で受け取れる様になります。link_toで飛ばした先のアクションで値を受け取る
posts_controller.rbdef new @post = Post.new @post.shop_id = params[:shop_id] end先ほどのurlから値を受け取ります。
form_with内でf.hidden_fieldを使い受け取った値を使う
new.html.erb<%= form_with(model: @post) do |f| %> ... <%= f.hidden_field :shop_id, :value => @post.shop_id %> <%= f.submit "投稿する" %> <% end %>
f.hidden_field
を用いてユーザーが入力することなくform_with
内でパラメータを引き渡します。
これでlink_to
で飛ばしたshop_id
をpostsのcreateアクションに引き渡すことができました。
- 投稿日:2020-02-25T18:05:59+09:00
「パーシャルを一部だけ非表示にしたい」`defined?`で分岐よりデフォルト値をパーシャル内に書く。が腹落ちした
はじめに
パーシャルの内容がほとんどおなじで、一部だけ表示を変えたい(追加したい、非表示にしたい)要件がでてきました。
たとえば、以下のようなときです。
posts#index
:「タイトル、公開日、書いた人」が確認できるusers#show
:ユーザーの記事一覧が「タイトル、公開日」で確認できる。けれど「書いた人」の列は表示させない画面のイメージ
posts#index
では、すべての列が表示されて、
タイトル 公開日 書いた人 タイトル 公開日 書いた人
users#show
では、「書いた人」の列が表示されません。
タイトル 公開日 タイトル 公開日 解決策1:
defined?
で条件分岐させる方法Railsのrenderでdefined?による分岐 - PIYO - Tech & Life -で紹介されていた「
defined?
をつかった分岐」をするとスッキリと意図どおりに書くことができて便利でした。index.html.haml= render "posts/list", posts: @user.posts within_name_column: trueshow.html.haml= render "posts/list", posts: @user.posts_list.html.haml%table %thead %tr %th タイトル %th 公開日 - if defined? within_name_column %th 書いた人 %tbody - posts.each do |post| %tr %td= post.title %td= l(post.created_at) - if defined? within_name_column %td= post.user.nameですが、いくつか微妙なところがありました。
true
でもfalse
でも定義されていれば真になる(値に意味がなくてモヤッとする)if within_name_column
と書きたい(defined?
が冗長におもえる)変数が定義されているかどうかを条件にするのでなく、ストレートに
true, false
で判断したいです。パーシャルの先頭にデフォルト値を設定すればスッキリした
_list.html.haml-# 初期値をfalseにしておくと、"未定義"状態がなくなる! - within_name_column ||= false %table %thead %tr %th タイトル %th 公開日 -# 条件式もスッキリした! - if within_name_column %th 書いた人 %tbody - posts.each do |post| %tr %td= post.title %td= l(post.created_at) - if within_name_column %td= post.user.nameスイッチをONにするときは、上述したものとおなじように
within_name_column: true
とすれば、意図した動作をします。なによりtrue
である意味が出ました。よいですね!index.html.haml= render "posts/list", posts: @user.posts within_name_column: trueおわりに
「パーシャルは、呼び出し元から渡された値で動くもの」という考えが強かったため、「パーシャル内でデフォルト値を持っておく」という方法は発見でした
パーシャル先頭に初期値を設定していることで、コードを読んだときに「初期値があるということは、呼び出し側でスイッチさせる仕様がある」ということも伝わってよいなあと感じました。
- 投稿日:2020-02-25T17:50:45+09:00
[rails] Modelに紐づく関連テーブル名一覧を取得するメモ
User.reflect_on_all_associations.map(&:name) => [:orders, :address, :payments] # has_one等を指定する事も出来る User.reflect_on_all_associations(:has_one).map(&:name) => [:address]
- 投稿日:2020-02-25T17:49:02+09:00
【Rails】carrierwaveの使用時「Nil location provided. Can't build URI.」が出てきた時の解決方法
- 投稿日:2020-02-25T15:26:25+09:00
【rails】画像の向きを整える方法
はじめに
初学者がポートフォリオ作成でハマったことをメモします。
投稿した画像の上下が逆になるバグが発生した。
画像アップロードにはActiveStorageを使用しています。環境
Ruby 2.6.3 ,Rails 5.2.4
方法
minimagickの設定で
auto_orient: true
を記述する。= image_tag review.avatar.variant(combine_options:{resize:"300x300^",crop:"300x300+0+0",gravity: :center, auto_orient: true}).processedこれでEXIF情報のOrientation属性(画像の向きを規定している)を変更してくれるみたいです。
最後に
誰かのお役にたてれば幸いです。
間違えている部分があればコメントお願いいたします。参考にした記事
https://tutorialmore.com/questions-2589404.htm
https://qiita.com/NaokiIshimura/items/a71cc118774e06d418c4
http://dqn.sakusakutto.jp/2009/02/jpegexiforientaion.html
- 投稿日:2020-02-25T15:26:25+09:00
【rails】画像の向きを整える方法(ActiveStorage)
はじめに
初学者がポートフォリオ作成でハマったことをメモします。
投稿した画像の上下が逆になるバグが発生した。
画像アップロードにはActiveStorageを使用しています。環境
Ruby 2.6.3 ,Rails 5.2.4
方法
minimagickの設定で
auto_orient: true
を記述する。= image_tag review.avatar.variant(combine_options:{resize:"300x300^",crop:"300x300+0+0",gravity: :center, auto_orient: true}).processedこれでEXIF情報のOrientation属性(画像の向きを規定している)を変更してくれるみたいです。
最後に
誰かのお役にたてれば幸いです。
間違えている部分があればコメントお願いいたします。参考にした記事
https://tutorialmore.com/questions-2589404.htm
https://qiita.com/NaokiIshimura/items/a71cc118774e06d418c4
http://dqn.sakusakutto.jp/2009/02/jpegexiforientaion.html
- 投稿日:2020-02-25T08:51:47+09:00
progate Rails学習コースⅨ-6の「self」について
本記事の概要
ProgateのRails学習コース内で、インスタンスメソッド内で使用するselfについて、
その仕様を自分なりに噛み砕いてまとめています。誰向けの記事か
selfの使い方について、Progate内の解説が簡素すぎて、よく分からなかった人向け(私がそうでした)
問題の箇所
Postsテーブル:id,content,user_id
Usersテーブル:id, name,emailposts.rbdef user return User.find_by(id: self.user_id) end# ターミナルでrails consoleを実行したのち、以下を実行 post = Post.find_by(id:1) post.user #結果=> id:1, name:hogehoge ~~~スライド内の解説
Postモデル内にその投稿に紐付いたuserインスタンスを戻り値として返すuserメソッドを定義しましょう。
インスタンスメソッド内で、self はそのインスタンス自身を指す「selfはそのインスタンス自身を指す」←?????
自分なりに処理の流れを追ってみた
まず、Progateのスライドでは、Controller内ではなくコンソールで、インスタンスメソッドであるuserを呼び出している点に注意です。
演習では、インスタンスメソッドであるuserの呼び出しは、posts_controllerで行います。
そちらでどう記述するか、を先に見てしまいましょう。以下になります。
posts_controller.rbdef show @post = Post.find_by(id: params[:id]) @user = @post.user endインスタンスメソッドuserを定義しているコードと合わせて、見てみましょう。
以下です。posts.rbdef user return User.find_by(id: self.user_id) endそして、スライドの解説文をもう一度。
インスタンスメソッド内で、self はそのインスタンス自身を指す
インスタンスメソッドuser内の self は、インスタンスメソッドuserを呼び出すインスタンス自身を指している、ということです。
実際にuserが使用されているcontrollerをもう一度見てみましょう。posts_controller.rbdef show @post = Post.find_by(id: params[:id]) @user = @post.user end@user = @post.user
↑↑まさにここで、インスタンスメソッドuserが呼び出されていますね。
そして、呼び出しているインスタンスは、@postです。インスタンスメソッドuser内の self は、
インスタンスメソッドuserを使用するインスタンスである@postを指している、
ということです。では、@postの中身は何かというと、
@post = Post.find_by(id: params[:id])
⇨「Postテーブルの中身を、idで検索して得られた結果」です。
Postsテーブルのカラムは、id,content,user_id であり、それぞれに値が入っています。・インスタンスメソッドuser内の self は、
インスタンスメソッドuserを使用するインスタンスである@postを指している
・@postの中身は、Postテーブルの中身を、idで検索して得られた結果それを踏まえて、再度、インスタンスメソッドuserの中身を見てみましょう。
posts.rbdef user return User.find_by(id: self.user_id) end⇨@postの中身から、user_idを取り出して(参照して、が正しいか?)、
Userテーブルについて、そのuser_idをidとして検索し、
その結果をreturnする
というのが、インスタンスメソッドuserの中身である、ということになります。Userテーブルにはuser_idというカラムは存在しませんが、Postテーブルのuser_idとUserテーブルのidが等しいため、
Userテーブルでの検索条件に@post.user_idを用いることで、PostテーブルとUserテーブルを関連づけた形の検索結果が得られる、ということになります。Progate以外での、selfの使用例
Qiitaの記事で、ズバリな解説をしてくださっているものがありましたので引用いたします。
https://qiita.com/leavescomic1/items/99f32f45cd04035f146c#%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89以下引用ーーーーーーーーーーーーーーーーーーーーーーーーーーーー
以下のusers_controllerの@userがインスタンスになります。
users_controller.rb@user = User.find(params[:id]) #findはインスタンスを探すメソッド #Userクラスから調べたいidに該当するユーザー情報をデータベースから取得しています。 @my_age = @user.too_young #@userというインスタンスにtoo_youngというメソッドを使っている。ここで、@userというインスタンスに対してtoo_youngというメソッドが使われています。
@userというインスタンスに使うメソッド....これがインスタンスメソッドとなります。もう一度user.rb内に記載されているtoo_youngメソッドを見てみましょう。
user.rbclass User < ApplicationRecord validates :username, presence: true validates :email, presence: true #ここがインスタンスメソッド def too_young if self.age >= 20 #20歳以上の場合 return "大人です!" else #20歳以下の場合 return "子供です!" end end endtoo_youngメソッド内に「self」というものがあります。
この「self」は何かというとusers_controller.rbで定義された@userのことです。
@userというインスタンスに対して「.(ドット)」で繋げてインスタンスメソッドを呼び出す時、インスタンスメソッド内では「self」が使え、self=呼び出し元のインスタンス(@user)となります。
今@userの中身は
user.rb
id: 1, username: "山田太郎", email: "hogehoge@example.com", age: 28
なので、self.ageでageカラムの値が呼びだされ、「28」という数字が返ってきます。引用ここまでーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
おわりに
Progateは、初学者にとって非常に便利な学習サイトですが、解説がシンプルすぎる箇所があります。
理解が曖昧だと感じたときは、その箇所を使ったコードをProgate以外で探して見ると、理解が深まります。
(更に、その部分について自分のローカル環境でコーディングして、改変してエラーを出す、などしてみるのが、最も仕様を理解できる手段です)今回の self がどのくらい重要かは正直今の知識ではよく分からないですが、
色々と調べてみて、「多分こういうことだろう」と理解できたのは自分にとってプラスになったと感じたので、
備忘録的な形で記事として残すこととします。
万が一、同じように詰まっている人がいたら、少しでも参考にしていただければと思います。
- 投稿日:2020-02-25T06:00:46+09:00
[Rails]NoMethodError の解決例
1.エラーの様子
エラー文を読むと下記のように言っています
・定義されていないメソッドがsignupコントローラのnewアクションに関連するファイルの中にあります。
※メソッドとは、正確に表現するとオブジェクトから値を"呼び出す動作"を示したもののことです。噛み砕いていうと配列の一要素を呼び出す動作のこととなります。さらに意訳すると呼び出した値(オブジェクト)と同義とみなすことができるため、そちらで理解すると下記で解説するシンボルと対比で覚えることができるためおすすめです。
例:配列user=[name,age,hair-color]に対しuser.nameとした場合、.nameがメソッドで意味はuser配列のname変数と定義した箇所を呼び出す動作となりますが、こういう塊が出てきたときは「この塊が意味しているのは、配列の中からメソッドがで呼び出してる値のnameだ!」ではなく、「この塊はnameという値だ」と理解するのをおすすめしています・app/view/new.html.hamlファイルに定義されてないメソッドのlsatnameなるものがありました。
・
lastname?
ではないですか(シンボルキーではなく数値有無の判定子じゃないですか?)
※判定子は、定義されないことによる数値が入ってこない現象(failse)に対し、rails機能で、エラーではなくnullとして判断するためエラーになりません。なので確かにlastname?
にするとこの部分のエラーは解消します。しかし、当初の目的の「数値の出し入れ」の機能は持たせることができません。2.原因とその調べ方
1.原因
シンボルキーの使用許可をし忘れていたことが原因でした(下記の3番目のミス)
2.原因の調べ方
NoMethodErororが出ている時点でルート設定はうまく行っているためrailsの命名規則にしたがっていると判断できます。(例えばusers_controllerと関係があるのはapp/view/usersフォルダの中のファイルのみという決まりがあります。さらに命名規則について詳しく知りたい方は下記のURLからrailsドキュメント(公式)のホームページを読んでみることをお勧めします。(とても説明が少ないため、ある程度railsを理解している方で公式のルールが確認したい方にのみおすすめします。)参考:railsドキュメント https://railsdoc.com/rails_base )
したがって間違っている可能性のあるファイルはsignup_controller、app/view/signupの中のファイル、:last_nameを定義したマイグレーションファイル、:last_nameを含んだ配列を記載したモデルファイルのどこかにあると考えられます。また、一般的な話として、マイグレーションファイルとモデルファイルは記載箇所が少ないためまず間違ってないことがほとんどで実質2択まで絞ることが出来ます。
さらにこのエラーの時は大抵下記の3つの原因に当てはまるため、signup_controllerかapp/view/signupの中のファイルどちらかのファイルで誤りを探してもらえればほとんど解決すると思います。1.コントローラによって定義されていない変数(:nameや@user.nameのようなもの)を媒介して値を入出力しようとしている。(エラー表示はNomethodErrorと出るためややこしいです。)
※例えば@user.nameを使いたければコントローラで@user=user.all(@useはuserテーブル全てのカラムを使用できる)と定義する。または、@user=user.nameで@userとして利用する必要があります2.変数をテーブルに入力したいのに出力用の変数のインスタンス変数(@userなど)を使用している。@userとして使用する変数(インスタンス変数)はviewで"呼びだす"ためのもので、viewで:nameと使用する変数(シンボルキー)は"入力してもらう"変数です。@userはインスタンス(=実体化した)と呼ぶくらいで、変化が終わった後のもの、つまり定義後の引用先(viewファイル)で値の変更はない変数となっていることを理解していると間違えがなくなります
※エラーの様子のところで説明した通り、インスタンス変数の一部をメソッドで呼び出したもの(@users.nameなど)を1つの塊として値(オブジェクト)と見なすと、シンボルも値(オブジェクト)であるため、"出すためのもの"か"入れるためのもの"という対比の関係に落とし込むことができ、viewファイルの記述で記入用の変数に間違ってインスタンス変数を使った(@をつけた)といったミスはなくなります3.悪意のある入力を弾くため(セキュリティを強くするため)、railsではコントローラ以外(=マイグレーションファイル)で定義された変数をそのまま使うためにはその値がコントローラで許可されている必要があるのだが、その過程が抜けてしまっている(ストロングパラメータの指定し忘れ)
3.解決方法
今回は:lastnameの使用許可の記述が抜けていたため、app/controllers/signup_controllerに下記の通りの記載を加えることでこのエラーは解消します
app/controllers/signup_controllerclass SignupController < ApplicationController before_action :user_params #この行を追加 #〜中略〜 private #この行から def user_params params.require(:user).permit(:lastname) end #この行まで追記 end (signup_controllerの全てのアクションで使用する必要があるため、あらかじめ定義しbefore_actionで全てに反映しています)
- 投稿日:2020-02-25T00:03:21+09:00
rails アプリ立ち上げで最初にやること
アプリ立ち上げで最初にやるのはターミナルを開いて
rails new アプリケーション名 -オプション名
私が使ってるオプション名はmysqlなので
rails new mangasuki -d mysql
となる。
バージョン指定するときは
rails 5.2.3 new mangasuki -d mysql
という風に記述すればバージョンの指定ができる。
数字の前後にアンダーバーをつける。