20210802のRubyに関する記事は15件です。

【初心者向け】rails 投稿機能解説!form_withやストロングパラメータを図で理解!

はじめに form_withをつかった投稿機能は、Rails 初学者がつまづきやすいポイントかと思います! 本記事では form_withを使った入力フォームの作成 、ストロングパラメータ、データの保存までを解説していきます。 図を織り交ぜていますので、イメージをつかみつつ理解を深めていきましょう 動作環境 Ruby 2.6.7 Rails 5.2.7 (動作としてはrails6系でも同様です) 実装する機能・仕様 フォームでタイトルと内容を入力し、データベースに保存する。 Blogモデルにtitle、bodyカラムを準備。 form_withを用いて入力データを送信する new.html.erbにてフォームを以下のように作成していきます。 blogs_controller.rb def new @blog = Blog.new end new.html.erb <h1>Blogs#new</h1> <%= form_with model: @blog, local: true do |f| %>  <!--タイトル入力フォーム生成--> <%= f.label :title %><br> <%= f.text_field :title %><br>  <!--内容入力フォーム生成--> <%= f.label :body %><br> <%= f.text_area :body %><br>  <!--投稿ボタン生成--> <%= f.submit %> <% end %> 実行画面 入力フォームのイメージ Blog.newの記述がありますが、これはBlogの新しい箱を作るイメージになります。このBlogの箱の中には空のtitle、bodyの箱を持っています。この空の箱をインスタンス変数@blogに格納して、フォームヘルパー(form_with)に渡していきます。 フォームヘルパーとは フォームヘルパーは入力フォームを簡単に作成できるように、あらかじめメソッド(処理)を用意してくれているものです。 f.text_fieldやf.text_area、f.submitなどがその例です。フォームをヘルパーなしで書こうとするとなかなか面倒になるので、とてもありがたい存在です 文字や値を入力したのちにCreate Blogのボタンを押すと、フォームヘルパーは入力値を該当する箱に入れていきます。 この作業を経てパラメータの一つが生成され、次にcreateアクションへ送信していきます。イメージとしては荷物パッキングをして次のアクションまで配送するイメージです。 パラメータとは ここで、パラメータについて少し触れます。 パラメータとは基本的にはアクション間で受け渡しされるデータのことを指します。 どのような情報が渡されているのかはターミナルで確認することができます。titleに"hoge"、bodyに"fuga"を入力してターミナルを確認すると以下のようになります。(一部抜粋) terminal Started POST "/blogs" for ...... : Processing by BlogsController#create as HTML Parameters: {"utf8"=>"✓", "authenticity_token"=>"..", "blog"=>{"title"=>"hoge", "body"=>"fuga"}, "commit"=>"Create Blog"} : : 今回はこの中でも Parameters: {"utf8"=>"✓", "authenticity_token"=>"..", "blog"=>{"title"=>"hoge", "body"=>"fuga"}, "commit"=>"Create Blog"} がパラメータになります。 『"〇〇"=>"××"』を一つのまとまりと考えます。上記を箱のイメージであらわすと となります。箱の中にそれぞれ矢印の右辺の情報が入っているイメージです。 このように、先ほど入力した情報がBlogの箱の中のtitleとbodyに格納されて、送信されていることが確認できます。 フォームの送信後createアクションでの挙動 ここからはcreateアクション内での処理を説明していきます。 blogs_controller.rb def create # ストロングパラメータで入力された値を取得 @blog = Blog.new(blog_params) # 保存 @blog.save # 保存後詳細ページに遷移 redirect_to blog_path(@blog) end private # ストロングパラメータ def blog_params params.require(:blog).permit(:title, :body) end 送られてきた箱をそのまま保存したい!!となりますが、railsではアクションごとに新しい箱を作成して移し替える作業を行う必要があります Blog.new(blog_params)のBlog.new()関しては前章の考え方と同様に、空の箱を作るイメージです。 かっこの中身は空の箱の中に、値をはじめから入れたいときに入力します。 ストロングパラメータ 今回はフォームで入力した値を空の箱に入れていきたいので、ここでストロングパラメータを定義したblog_paramsを呼び出しています。 params.require(:blog).permit(:title, :body)は3つに分割して考えていきます。 params パラメータ全体を呼び出します。 .require(:blog) パラメータの中で、どの要素(大きな箱)を選択するかを宣言します。今回の場合、4つの箱(utf8, authenticity_token, blog, commit)の中からblogを選択するという意味になります。 .permit(:title, :body) 選択した要素(大きな箱)内に含まれるパラメータの中でどの情報の保存を許可するのかを選択します。今回の場合、blogの箱の中にあるtitleとbodyについて保存するという意味になります。 ストロングパラメータはなぜ必要? ストロングパラメータを設定することで、不要な情報が保存されてしますことを防ぎます。 仮に悪意のあるユーザーがtitle、body以外の箱を自分で作って送信してきたとします。ストロングパラメータを設定していなかった場合、データベースにはそのカラムは存在していないので、その情報を保存するときにエラーを吐いてしまいます。ストロングパラメータで、必要な情報のみを選別しているといことになります。システムの根幹にもなるので、他の場所から呼び出して書き換えができないようにprivate下に書くことが一般的です。 これらをまとめると、Blog.new(blog_params) は『送られてきたパラメータの中から、blogの中のtitleとbodyを取り出して、新しい箱に入れる』ということになります。したがって、createアクションのイメージを描くと以下のようになります。 これでフォームの入力~データの保存が完了です! おわりに 今回はフォームの入力から保存までの流れを図メインでまとめてみました! イメージはつかめましたでしょうか? 少しでも参考になればと思います
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

技術書「Rubyソースコード完全解説」 と 「docker で ruby」構築

今まで買ってよかった技術書を紹介しよう! https://qiita.com/official-events/d409f91fc8b9b44cefb4 の企画に参加する記事です。 Docker上のみでシステムを作るときの構成 https://qiita.com/official-events/339b6440dbd578f4f66f 参加記事です。 協賛企画 bookmeterで協賛企画をはじめました。 今まで買ってよかった技術書を紹介しよう! https://bookmeter.com/events/8648 技術書は、紹介してもなかなか反応がなく、嫌気が指すかもしれません。 amazonに1万冊感想を書くという目標を立てたとき、技術書ばかりを書いていて、 反応がほとんどなく、底なし沼に石を投げているような感覚に襲われたことがあります。 そこで5つの手を打ちました。 1つは、芥川賞、直木賞を読むことにより、文学の投稿をするようにしました。 芥川賞、直木賞を読む コミュニティ https://bookmeter.com/communities/332458 芥川賞、直木賞を読む イベント https://bookmeter.com/events/786 2つめは、オフライン行事に参加することでした。 2013年4/10 【第19回 名古屋de朝活読書会】 https://bookmeter.com/events/150 3つ目は、オンライン行事に参加することでした。 新潮文庫夏の100冊2014を読破しよう! https://bookmeter.com/events/1399 100冊まとめては結構捗る。 4つ目は、オンライン行事を主催することでした。 第1回お茶(緑茶・紅茶・烏龍茶)を飲みながら読書会 https://bookmeter.com/events/1310 5つ目は、絵本に焦点を絞ったことでした。 【読メ絵本部】 https://bookmeter.com/communities/334325 これは、小坂井大輔さんが主催されていた朝活読書会で絵本の紹介があったときに、 かこさとし が、技術士だということを知ったのに衝撃を受けて、かこさとしの 絵本の全部読み(紙芝居以外は完読)しようとしたことによります。 Rubyソースコード完全解説 https://bookmeter.com/books/32780 Rubyソースコード完全解説(html版) https://i.loveruby.net/ja/rhg/book/ ご紹介に基づいて拝見しました。 ruby / ruby @ gitnub https://github.com/ruby/ruby bash $ docker run -it gcc /bin/bash How to compile and install If you want to use Microsoft Visual C++ to compile Ruby, read win32/README.win32 instead of this document. Run ./autogen.sh to generate configure, when you build the source checked out from the Git repository. Run ./configure, which will generate config.h and Makefile. Some C compiler flags may be added by default depending on your environment. Specify optflags=.. and warnflags=.. as necessary to override them. Edit include/ruby/defines.h if you need. Usually this step will not be needed. Optional: Remove comment mark(#) before the module names from ext/Setup. This step is only necessary if you want to link modules statically. If you don't want to compile dynamic extensions (probably on architectures which do not allow dynamic loading), remove comment mark from the line "#option nodynamic" in ext/Setup. Usually this step will not be needed. Run make. On Mac, set RUBY_CODESIGN environment variable with a signing identity. It uses the identity to sign ruby binary. See also codesign(1). Optionally, run 'make check' to check whether the compiled Ruby interpreter works well. If you see the message "check succeeded", your Ruby works as it should (hopefully). Run 'make install'. This command will create the following directories and install files into them. ${DESTDIR}${prefix}/bin ${DESTDIR}${prefix}/include/ruby-${MAJOR}.${MINOR}.${TEENY} ${DESTDIR}${prefix}/include/ruby-${MAJOR}.${MINOR}.${TEENY}/${PLATFORM} ${DESTDIR}${prefix}/lib ${DESTDIR}${prefix}/lib/ruby ${DESTDIR}${prefix}/lib/ruby/${MAJOR}.${MINOR}.${TEENY} ${DESTDIR}${prefix}/lib/ruby/${MAJOR}.${MINOR}.${TEENY}/${PLATFORM} ${DESTDIR}${prefix}/lib/ruby/site_ruby ${DESTDIR}${prefix}/lib/ruby/site_ruby/${MAJOR}.${MINOR}.${TEENY} ${DESTDIR}${prefix}/lib/ruby/site_ruby/${MAJOR}.${MINOR}.${TEENY}/${PLATFORM} ${DESTDIR}${prefix}/lib/ruby/vendor_ruby ${DESTDIR}${prefix}/lib/ruby/vendor_ruby/${MAJOR}.${MINOR}.${TEENY} ${DESTDIR}${prefix}/lib/ruby/vendor_ruby/${MAJOR}.${MINOR}.${TEENY}/${PLATFORM} ${DESTDIR}${prefix}/lib/ruby/gems/${MAJOR}.${MINOR}.${TEENY} ${DESTDIR}${prefix}/share/man/man1 ${DESTDIR}${prefix}/share/ri/${MAJOR}.${MINOR}.${TEENY}/system If Ruby's API version is 'x.y.z', the ${MAJOR} is 'x', the ${MINOR} is 'y', and the ${TEENY} is 'z'. NOTE: teeny of the API version may be different from one of Ruby's program version You may have to be a super user to install Ruby. If you fail to compile Ruby, please send the detailed error report with the error log and machine/OS type, to help others. Some extension libraries may not get compiled because of lack of necessary external libraries and/or headers, then you will need to run 'make distclean-ext' to remove old configuration after installing them in such case. bash # git clone https://github.com/ruby/ruby.git Cloning into 'ruby'... remote: Enumerating objects: 507408, done. remote: Counting objects: 100% (1352/1352), done. remote: Compressing objects: 100% (788/788), done. remote: Total 507408 (delta 595), reused 1220 (delta 541), pack-reused 506056 Receiving objects: 100% (507408/507408), 244.97 MiB | 4.30 MiB/s, done. Resolving deltas: 100% (388985/388985), done. # cd ruby # ./autogen.sh # ./configure checking for ruby... false configure: error: cannot run /bin/bash tool/config.sub いまここ。 参考資料(reference) 人生で影響を受けた本100冊。Youtube(3) https://qiita.com/kaizen_nagoya/items/16af53acbb147a94172e 情報工学の専門家に読んで欲しい月刊「技術士」の記事544 https://qiita.com/kaizen_nagoya/items/29ea1465cc228de17ca6 技術士が書いた本・冊子類(IT業界・製造業向け)200+3 https://qiita.com/kaizen_nagoya/items/774665826e8a91ad4bd7 新人の方によく展開している有益な情報 https://qiita.com/kazuo_reve/items/d1a3f0ee48e24bba38f1 第11回 TOPPERS活用アイデア・アプリケーション開発コンテスト https://qiita.com/kaizen_nagoya/items/91162a9b258a2a06f5e0 TOPPERSに関連する書籍なら、この部門への投稿の表題を変えて、コンテストに応募するのも手かも。 あなたもdocker, 私もdocker https://qiita.com/kaizen_nagoya/items/8f2746f10f30b575d0a8 開発環境を豊かにする開発事例 過去・現在・未来 https://qiita.com/kaizen_nagoya/items/d9bf0c2c671fe7f1c749 Microsoftとの歴史 Cコンパイラを中心に https://qiita.com/kaizen_nagoya/items/d7c0cc257e99de0573cf Qiitaエンジニアフェスタ_ブラウザ選手権 https://qiita.com/kaizen_nagoya/items/98c4c7f911aa47465087 Qiitaエンジニアフェスタ_StaticWebApps に参加するまで https://qiita.com/kaizen_nagoya/items/1a1f53926325d872821f TOPPERS ソースを積み上げよう https://qiita.com/kaizen_nagoya/items/65c15aed086f2da0928d
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

binding.pryを使えるようになりたい!2

はじめに 本記事は、昨日投稿した続きで、 「binding.pry」の使い方をまとめたものになります。 前回の投稿もご参照ください。 「binding.pry」の目的 たとえ、「binding.pry」が万能だとしても、 確認できることは限られています。 目的(私が思いつくものです。他にもあると思います。) ①paramsの中身の確認 ②「binding.pry」の後に、if文があれば、true or falseの指示が出せているかどうか ③エラー内容の確認 ④インスタンス変数の中身の確認 結論としては、 何かの中身や結果が期待するものかどうかを調べたい時 エラーの原因はどこにあるのかを探したい時 が目的となります。 何ができる? ここのコードが間違えているため、このように修正しなさい!! という直接的にエラーを解決できるものではありません。 ここではないかという目星をつけ、 「ここは間違えていない!ここも間違えていない!ここは間違っている!」 という風に、選択肢を潰していく このようなことができます。 指定した場所でエラーが起きるかどうかを確認するものです。 どこで使用できる? コントローラーでもビューでもモデルでも使用できます。 特にモデルでは、自作のメソッドが役割を果たせているかを確認する際に、 「binding.pry」は多く使用されます。 また、試したいコードの部分の手前に「binding.pry」を置きましょう。 エラー内容の確認 class OrdersController < ApplicationController def index @order = Order.new end def create @order = Order.new(order_params) binding.pry if @order.valid? @order.save return redirect_to root_path else render 'index' end end private def order_params params.require(:order).permit(:price) end end 前回投稿したものを引用しますと、 if @order.valid? から「binding.pry」はエラーを調べることができます。 エラーがあれば「false」、なければ「true」ということは、前回に投稿しました。 「false」だった場合で、エラーの内容を確認したい時は、 errors.full_messagesを記述しましょう。 [1] pry(#<OrdersController>)> @order.valid? => false [2] pry(#<OrdersController>)> errors.full_messages => Price can't be blank エラーが実際に画面に表示されたときも、 「Price can't be blank」のような文章が現れるはずです。 errors.full_messages についてはよく使用するので、ここは暗記でも良いのでは? と思い、私は暗記しました。 終わり 昨日に引き続き「binding.pry」の深堀を行いました。 何一つわからなかった昨日とは大きく成長したように思えます。 今回のように理解していなく、不安な要素は、 理解した上で、深堀することで、 苦手から得意になると私はそう思います。 どんどん得意を増やします。 引き続きがんばりましょう!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsの環境構築

はじめに 環境構築はPCを購入した後、一回やれば何度も毎回やる必要のない作業です。 ですので全く作業工程を覚えられる気がしないので、私が初めて行ったRailsで開発するための環境構築を忘れないうちに、ざっと書いておきます。 ちなみにMacでiOSはCatalina以降のやり方になります。 よろしくお願いします。 Command Line Toolsをインストール まず、Command Line Toolsを入れる前に下記のコマンドをターミナルで実行します。 ターミナル # zshをデフォルトに設定 % chsh -s /bin/zsh # ログインシェルを表示 % echo $SHELL # 以下のように表示されれば成功 /bin/zsh もしパスワードを求められたら、PCのパスワードを入力します。 さあ、Command Line Toolsをインストールします。Command Line ToolsとはWebアプリケーション開発に必要なソフトウェアをダウンロードするために必要となる機能です。 下記のコマンドをターミナルに打ち込みます。 ターミナル % xcode-select --install するとホップアップが出てくるのでインストールをクリック →仕様許諾契約が出てきたら「同意する」をクリック するとCommand Line Toolsのダウンロードが開始します。 完了したら次に進みます。 Homebrewをインストール ただこのHomebrewのインストールの前にMacのチップがM1チップの場合下記の設定を行っておくことをおすすめします。 M1チップの場合 ①Finderを開けて「ターミナル」を検索 ②ターミナルアプリを2本指でタップ、もしくはマウスの場合は右クリックでメニューを表示させる。 ③「情報を見る」をクリック ④「Rosettaを使用して開く」にチェックを入れる ⑤一度ターミナルを終了して、もう一度起動させる ここまでできたら、あとはIntelチップの方と同じように進めていきます。 それではHomebrewをインストールしていきます。(Intelチップの人はここから作業する) 下記のコマンドを一つずつ実行していきます。 ターミナル % cd # ホームディレクトリに移動 % pwd # ホームディレクトリにいるかどうか確認 % /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" # コマンドを実行 処理に時価がかかる可能性があるので慌てず待ちます。 パスワードの入力を求められたらPCのパスワードを入力します。 入力しても文字が入力されていないように見えるかもしれませんが、入力はされています。 入力できたらエンターキーを押します。 「Press RETURN to continue or any other key to abort」という文章が出てきたらエンターキーを押します。 プロンプトが現れ入力待ち状態になれば成功です。 下記コマンドでインストールできているか確認します。 ターミナル % brew -v Homebrew 2.5.1 # 数字は異なる場合があります。 下記コマンドでバージョンを最新にします。 ターミナル % brew update 下記のコマンドで権限を変更します。 ターミナル % sudo chown -R `whoami`:admin /usr/local/bin 最新バージョンのRubyをインストール まずはRubyの土台となる、rbenvとruby-buildをHomebrewを用いてインストールします。 ターミナル % brew install rbenv ruby-build rbenvをどこからでも使用できるように下記コマンドを実行します。 ターミナル % echo 'eval "$(rbenv init -)"' >> ~/.zshrc このコマンドでzshrcという設定ファイルを変更しました。 このファイルの修正内容を反映させるために、下記コマンドで再度読み込みをさせます。 ターミナル % source ~/.zshrc 続いてターミナルのirbで日本語入力を可能にする設定を行うために下記コマンドで「readline」をインストールします。 ターミナル % brew install readline readlineもどこからでも使用できるようにします。 ターミナル % brew link readline --force rbenvを使ってRubyをインストールします。 今回は2.6.5のバージョンのRubyをインストールします。 ターミナル % RUBY_CONFIGURE_OPTS="--with-readline-dir=$(brew --prefix readline)" % rbenv install 2.6.5 このコマンドは10分程度かかる場合があるコマンドなので気長に待ちましょう。 私は心配になって変に触って失敗しました。 インストールしたRuby 2.6.5を使用するために下記コマンドを実行します。 ターミナル % rbenv global 2.6.5 これでバージョンの指定ができたのでrbenvを読み込んで、変更を反映させます。 ターミナル % rbenv rehash Rubyのバージョンを下記コマンドで確認します。 ターミナル % ruby -v 2.6.5が表示されればOKです。 MySQLをインストール 下記コマンドでMySQLを導入します。 ターミナル % brew install mysql@5.6 このコマンドも時間がかかります。 完了したら次は自動起動させる設定をします。 というのもPCを再起動するたびにMySQLは起動し直す必要があるためです。面倒なので自動で起動してくれるようにします。 ターミナル % mkdir ~/Library/LaunchAgents % ln -sfv /usr/local/opt/mysql\@5.6/*.plist ~/Library/LaunchAgents % launchctl load ~/Library/LaunchAgents/homebrew.mxcl.mysql\@5.6.plist 続いてmysqlをどこからでも実行できるコマンドmysqlを実行できるようにします。 下記コマンドを実行します。 ターミナル % echo 'export PATH="/usr/local/opt/mysql@5.6/bin:$PATH"' >> ~/.zshrc # mysqlのコマンドを実行できるようにする設定 % source ~/.zshrc # 設定を読み込むコマンド % which mysql # mysqlのコマンドが打てるか確認する # 以下のように表示されれば成功 /usr/local/opt/mysql@5.6/bin/mysql 下記コマンドでMySQLが起動しているか確認します。 ターミナル % mysql.server status # MySQLの状態を確認するコマンド # 以下のように表示されれば成功 SUCCESS! MySQL running shared-mime-infoをインストール 下記コマンドでshared-mime-infoをインストールします。 ターミナル % brew install shared-mime-info Railsをインストール まずはgemを管理するためのbundlerをインストールする必要があります。 下記コマンドを実行します。 ターミナル % gem install bundler --version='2.1.4' 続いて下記コマンドでRailsをインストールします。 ターミナル % gem install rails --version='6.0.0' このコマンドも時間がかかります。 下記コマンドでrbenvを読み込んで変更の反映をさせておきます。 ターミナル % rbenv rehash Railsが正常にインストールされているか下記コマンドで確認します。 ターミナル % rails -v Rails 6.0.0 # 「Rails」のあとに続く数字は変わる可能性があります Node.jsをインストールする 下記コマンドでNode.jsをインストールします。 Railsを動かすためにNode.jsは必要です。 ターミナル % brew install node@14 さらに下記コマンドでNode.jsへのパスを設定します。 ターミナル % echo 'export PATH="/usr/local/opt/node@14/bin:$PATH"' >> ~/.zshrc % source ~/.zshrc 下記コマンドでNode.jsがインストールされているか確認できます。 ターミナル % node -v v14.15.3 # 数値は異なる場合があります yarnをインストール yarnはプログラム同士の関係性を管理する役割で用いられるものです。 下記コマンドでyarnをインストールします。 ターミナル % brew install yarn 下記コマンドでインストールできているか確認します。 ターミナル % yarn -v これで完了です。 最後に あくまでこれは私が初めて環境構築をしたときにやった工程を記したものです。 次にPCを買い換える時まで使うことはないかなと思いますし、そのときでは少しやり方が違ってたりするかもしれませんね。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Ruby on rails]タグ付け機能② タグをリンクにしてタグで検索(複数タグ)

やりたいこと ①投稿に対して複数タグを付けれるようにする(別記事で実装済) ②タグをリンクにして、検索できるようにする。リンクになってるタグを押すと、 そのタグを付与してる記事一覧が表示される 複数タグの投稿 投稿一覧画面でタグの一覧と、記事数の表示 タグを押すと、検索ができ、そのタグがついてる投稿を検索できる 投稿詳細画面 ①の複数のタグをつけて記事を投稿する機能については以下の記事で行っています。 今回はその続きです。 ルーティング記述 route.rb # タグの検索で使用する get "search_tag"=>"posts#search_tag" コントローラー記述 posts_controller.rb def search_tag #検索結果画面でもタグ一覧表示 @tag_list=Tag.all        #検索されたタグを受け取る @tag=Tag.find(params[:tag_id])         #検索されたタグに紐づく投稿を表示 @posts=@tag.posts.page(params[:page]).per(10) end 表示してるタグをリンクにする index.html.erb <!--タグリスト--> <% @tag_list.each do |list|%> <%=link_to list.name,search_tag_path(tag_id: list.id) %> <%="(#{list.posts.count})" %><% end %> show.html.erb <!--タグ--> <% @post_tags.each do |tag| %> <%= link_to tag.name,search_tag_path(tag_id: tag.id)%><%="(#{tag.posts.count})" %><% end %> view(検索結果の表示 <div class="container"> <h5>タグが<%=@tag.name%>の投稿一覧</h5> <!--タグリスト--> <% @tag_list.each do |list|%> <%=link_to list.name,search_tag_path(tag_id: list.id) %> <%="(#{list.posts.count})" %><% end %> <% @posts.each do |post| %> <!--投稿はカードで囲む--> <div class="card"> <div class="card-body"> <!--タイトル表示される文字数は25文字までにしてます--> <h6 class="card-title"> <%=link_to post_path(post.id) do %><%= post.title.truncate(25) %> <% end %> </h6> <!--お気に入り、コメント数、投稿者は部分テンプレ--> <div id="<%=post.id %>"><%= render 'favorites/favorite', post: post %></div> </div> </div> <% end %> <div class="pagination pagination-sm justify-content-center"> <%= paginate @posts %></div> </div> <style> .card{ padding:0; margin:0; border:none; } h6 { /*線の種類(実線) 太さ 色*/ border-bottom: solid 3px black; } </style> 終わり 以上で完了です。 とても参考にさせていただきました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Ruby on rails]タグ付け機能① 複数のタグ付け

やりたいこと ①投稿に対して複数タグを付けれるようにする ②タグをリンクにして、検索できるようにする。リンクになってるタグを押すと、 そのタグを付与してる記事一覧が表示される 複数タグの投稿 投稿一覧画面でタグの一覧と、記事数の表示 タグを押すと、検索ができ、そのタグがついてる投稿を検索できる 投稿詳細画面 タグを一個だけ付与するのは、別記事で投稿しました。 複数タグの実装はかなり難しかったのでまとめていきます。 ①テーブル定義 一応、以下の感じです。 タグ:投稿=1:N(複数) 投稿:タグ=1:N(複数) の多 対 多 になるので、 中間テーブルであるPostTagを用意して、それぞれの外部キーを持たせてます。 ①モデル/マイグレーションファイル作成 モデル作成 rails g model Tag name:string rails g model PostTag post:references tag:references マイグレーションファイル tagのマイグレーションファイル class CreateTags < ActiveRecord::Migration[5.2] def change create_table :tags do |t| t.string :name,null: false t.timestamps end end end post_tagsのマイグレーションファイル class CreatePostTags < ActiveRecord::Migration[5.2] def change create_table :post_tags do |t| t.references :post, foreign_key: true t.references :tag, foreign_key: true t.timestamps end # 同じタグを2回保存するのは出来ないようになる add_index :post_tags, [:post_id, :tag_id], unique: true end end add_index :post_tags, [:post_id, :tag_id], unique: true これは、複合キーインデックスで、この記述で同じタグを2回保存できないようにしています。 ここで、rails db:migrateして、続いてモデルファイルを記載します。 モデルファイル tag.rb class Tag < ApplicationRecord has_many :post_tags,dependent: :destroy, foreign_key: 'tag_id' # タグは複数の投稿を持つ それは、post_tagsを通じて参照できる has_many :posts,through: :post_tags validates :name, uniqueness: true, presence: true end 初めてthrough〜を見たときはなんのこっちゃでしたが、、だいぶ理解できるようになってきました! 中間テーブルは、”仲介役”という風に考えるようにしてから、何だかわかるようになってきた気がします。 post_tag.rb class PostTag < ApplicationRecord belongs_to :post belongs_to :tag validates :post_id, presence: true validates :tag_id, presence: true end validates〜_のところはPostとTagの関係を構築する際、2つの外部キーが存在することは絶対なので、 バリデーションを貼るそうですが、無くても問題ない気がしています(by初心者) これまでの中間テーブルでもvalidationつけてないので。 post.rb # タグのリレーションのみ記載 has_many :post_tags,dependent: :destroy has_many :tags,through: :post_tags ここからが難しかった・・ 何書いてあるかわからないので1行ずつ見ていきます。 ①コントローラー記述 post_controller.rb def create @post = Post.new(post_params) @post.user_id=current_user.id # 受け取った値を,で区切って配列にする tag_list=params[:post][:name].split(',') if @post.save @post.save_tag(tag_list) redirect_to posts_path(@post),notice:'投稿完了しました:)' else render:new end tag_list=params[:post][:name].split(',') なんかpaizaで勉強した記憶があるsplit..確か分割して配列を作ってくれるようやつだったように思います。 「splitとは」 1番目の引数に指定したパターンに従って文字列を分割し、分割された各部分文字列を要素とする配列を取得します。 @post.save_tag(tag_list) save_tagなんてそんなメソッドがあるのか・・・と思っていましたが違います!!!!! @post.saveの後に書いてあるから、紛らわしいですね・・ save_tagの働きについては、モデルファイルで定義してます。 タグで入力した値を配列に収めてる(tag_list)を引数としてモデルファイルに渡します。 ①問題のモデルファイル ここがすごく難しい。。。 def save_tag(sent_tags) # タグが存在していれば、タグの名前を配列として全て取得 current_tags = self.tags.pluck(:name) unless self.tags.nil? # 現在取得したタグから送られてきたタグを除いてoldtagとする old_tags = current_tags - sent_tags # 送信されてきたタグから現在存在するタグを除いたタグをnewとする new_tags = sent_tags - current_tags # 古いタグを消す old_tags.each do |old| self.tags.delete Tag.find_by(name: old) end # 新しいタグを保存 new_tags.each do |new| new_post_tag = Tag.find_or_create_by(name: new) self.tags << new_post_tag end end current_tags = self.tags.pluck(:name) unless self.tags.nil? unless~は「タグが存在してるか?」を確認しています。 ※投稿フォームでタグが入力されたか?を聞いてるわけではないので注意です。(ややこしいですが) タグが存在している場合には、current_tagsに、「タグの名前を配列として」全て取得します。 「plunk」とは?   簡単にいうとカラムの中身を展開してくれる https://qiita.com/k-o-u/items/31e4a2f9f5d2a3c7867f old_tags = current_tags - sent_tagsここでは、「今あるタグ」から「新たに送られてきたタグ」を引いて、 「old_tag」に代入しています。 例えば、既に 「ネズミ」 「お花」 「コアラ」 というタグが存在していて、新たに、 「お花」 「ユニコーン」 というタグが登録されたら old_tagには、「ネズミ」「コアラ」が入ります。 new_tags = sent_tags - current_tags ここで、new_tagsに「ユニコーン」が入ります。 old_tags.each do |old|〜で古いタグを消します。 今回の投稿記事付与したタグは 「お花」、「ユニコーン」です。 old_tagsに入ってる 「ネズミ」「コアラ」には用がありませんのでサヨナラします。 new_tags.each do |new|〜で新しいユニコーンというタグを保管します。 (以下は自分なりの解釈ですので気にしないでください。) モデルファイルを通過した時点で、手元に残ったタグは、 「お花」、「ユニコーン」です。 さらに、「ユニコーン」については「これは新しいタグ!」と判断されています。 モデルファイルは、なんだか気高い?裁判所のような?イメージです。 ①タグの表示・viewとコントローラー タグを表示していきます。(リンクは未実装です) 投稿一覧画面 postのコントローラー def index @posts = Post.page(params[:page]).per(10) @tag_list=Tag.all end app/views/posts/index.html.erb <!--タグリスト--> <% @tag_list.each do |list|%> <%=list.name %> <%="(#{list.posts.count})" %><% end %> 投稿一覧画面で投稿に紐づくタグを表示 <% @posts.each do |post| %> <i class="fas fa-tag"><%= post.tags.map(&:name).join(', ') %></i> <%= post.tags.map(&:name).join(', ') %>の部分、 最初、<%= post.tags.name %>にしてたのですが、エラーになってしまいました。 確かに、タグは複数ついてるので、<%= post.tags.name %>では取り出せないんだろうな。とは理解しました。 mapとは??&:とは??joinとは?? <%= post.tags.map(&:name).join(', ') %> 現状、postにタグは複数ついていて、配列になってます。['お花','ゴリラ','カエル']みたいな。 さて、これを取り出して、表示させたい。 map(&:name)は、配列の要素1つ1つを:nameの型にする というような意味のようです。 例を見るとわかりやすいです。 例:['a' ,'b'].map(&:upcase) #=> ["A", "B"] なので今回は、map(&:name)の部分で["お花","ゴリラ","カエル"]と文字列にされてるのだと思います。:nameはstring型にしてるので。 そしてjoin(', ')指定した文字で区切って連結してくれます。 "お花,ゴリラ,カエル"となってくれるわけですね 詳細画面での表示 posts_controller.rb def show @post = Post.find(params[:id]) @post_comment=PostComment.new @post_tags = @post.tags end posts/show.html.erb <% @post_tags.each do |tag| %> <%=tag.name%><%="(#{tag.posts.count})" %><% end %> ①編集機能 忘れてました.. <div class="field"> <%= f.label"タグ (,で区切ると複数タグ登録できます)" %> <%= f.text_field :name,value: @tag_list,class:"form-control"%> </div>  <div class="actions" style="margin:20px 0;"> <%= f.submit "投稿",class:"btn btn-outline-primary btn-block" %> </div> <% end %> value: @tag_listにしてあげないと、フォームに何も入ってない状態になってしまいます。 posts_controller.rb def edit @post = Post.find(params[:id]) # pluckはmapと同じ意味です!! @tag_list=@post.tags.pluck(:name).join(',') end def update @post = Post.find(params[:id]) tag_list=params[:post][:name].split(',') if @post.update(post_params) @post.save_tag(tag_list) redirect_to post_path(@post.id),notice:'投稿完了しました:)' else render:edit end end これで、編集機能もOKです!!! ひとまず終わり タグをリンクにして、投稿を取り出す手順については②の記事で説明します! とても参考にさせていただきました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】コントローラーのリファクタリング

はじめに ポートフォリオで、コントローラーのリファクタリングをやったので、備忘録として記事を書きます。 環境 ・Ruby 2.6.3 ・Ruby on Rails 5.2.5 リファクタリング1つ目 concemsを使う 共通記述を複数のコントローラーで使う時にやる app/controllers/concernsにファイルを追加し、必要箇所で読み込ませる controllers/concerns/search.rb module Search extend ActiveSupport::Concern def search @keyword = params[:word] redirect_to request.referer, notice: "検索文字を入れて下さい" if @keyword.blank? searcher = Searcher.new(params[:word].split(/[[:blank:]]+/)) @users = Kaminari.paginate_array(searcher.users).page(params[:page]).per(12) @groups = Kaminari.paginate_array(searcher.groups).page(params[:page]).per(12) @posts = Kaminari.paginate_array(searcher.posts).page(params[:page]).per(12) end end controllers/user/searches_controller.rb class User::SearchesController < ApplicationController include Search before_action :search end controllers/admin/searches_controller.rb class Admin::SearchesController < ApplicationController include Search before_action :search end これで同じ記述の箇所はスッキリ〜〜 リファクタリング2つ目 application_controller.rbにかいて継承 複数のコントローラに同じ処理が記述されている場合(継承)に役立つ controllers/user/●●●●●_controller.rb class ●●●●●Controller < ApplicationController before_action :authorize_owner private def authorize_owner redirect_to root_path unless current_user.owner? end end authorize_ownerメソッドが定義されていて、このメソッドを複数のコントローラーで使うよ!って時に application_controller.rbに記載して継承すれば、記述量少なくなります。 ※今回はauthorize_ownerメソッド使ってるけど、例として使っているのでどんなメソッドでもいい controllers/user/application_controller.rb class ApplicationController < ApplicationController private def authorize_owner redirect_to root_path unless current_user.owner? end end ↓継承したいコントローラーに。 controllers/user/●●●●●_controller.rb class ●●●●●Controller < ApplicationController before_action :authorize_owner end リファクタリング3つ目 callbackを利用して共通化 定義したメソッドをbefore_actionなどで共通化させちゃう方法 複数のアクションに同じ処理が記述されている場合に役立つ controllers/user/●●●●●_controller.rb class User::PostsController < ApplicationController before_action :set_group, only: %i[new index show create update destroy] before_action :set_post, only: %i[show update destroy] def new @post = Post.new end def index @posts = @group.posts.includes(:user).order(updated_at: :desc).page(params[:page]).per(12) end def show @comment = Comment.new respond_to do |format| format.html do end format.csv do send_data render_to_string, filename: "投稿詳細.csv", type: :csv end end end 一部アクション割愛 private #ここで記述が重なるコードをメソッド化 def set_group @group = Group.find(params[:group_id]) end def set_post @post = Post.find(params[:id]) end #ここまで #これをbefore_actionで呼び出しちゃえばおk end リファクタリング4つ目 王道モデルにメソッド定義 長ったらしいコードをモデルに定義してコントローラーをすっきりしようよ作戦 controllers/user/homes_controller.rb class User::HomesController < ApplicationController def top @group_ranks = Group.find(GroupUser.group(:group_id).order("count(group_id) desc").limit(6).pluck(:group_id)) @admins = Admin.first(6) end end #この部分をメソッド化してスッキリさせる# Group.find(GroupUser.group(:group_id).order("count(group_id) desc").limit(6).pluck(:group_id)) モデルに定義 models/group.rb # ランキング用メソッド def self.all_group_ranks find(GroupUser.group(:group_id).order("count(group_id) desc").limit(6).pluck(:group_id)) end コントローラーに呼び出す controllers/user/homes_controller.rb class User::HomesController < ApplicationController def top @group_ranks = Group.all_group_ranks # Group.rbでメソッド定義 @admins = Admin.first(6) end end 以上自分が実際にやったリファクタリングでした〜〜
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails]N+1問題を対処する

N+1問題って聞いたことはありますか? N+1問題はかなり怖い問題で、ぼくはポートフォリオ作成のときに、N+1問題に直面しました。 そのときに、調べた内容をぼくの理解の範囲で、アウトプットしていきます。 N+1問題とは そもそもN+1問題とはどんな問題のことをいうのでしょうか? データベースからデータベースを取り出すときに、大量のSQLが発行されて、動作が重くなる問題のことです。 たとえば、usersテーブルとpostsテーブルで、下記のようなアソシエーションがあったとします。 models/user.rb class User < ActiveRecord::Base has_many :posts end models/post.rb class Post < ActiveRecord::Base belongs_to :user end で、投稿の一覧を表示していきます。 Postモデルから全データ取得して、それをeach文で回していきます。 controllers/posts_controller.rb class PostsController < ApplicationController def index @posts = Post.all end end views/posts/index.html.erb <%= @posts.each do |post| %> <%= post.content %> <%= post.user.name %> <% end %> これで、このビューにアクセスし、ログを確認してみましょう。 User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] : このようにPostの数だけ、post.userを探すため、SQLが大量に発行されます。 勉強段階の開発環境等では、データ数もそこまで多くないので、そこまで問題になりませんが、実際に運用していくとなると、投稿数も増えていくことが想定されます。 データ数が、1000になると考えると、毎回1000件のデータ全てにSQLを発行していたら、遅くなるのは明白ですね。 なにも対策をとらないとデータ量が増えるにつれて、動作が遅くなる問題が、N+1問題です。 対策 では、N+1問題がどんなものか分かったところで、対策方法をみていきましょう! includesメソッドを使っていきます。 includesメソッドは、`アソシエーションの関連付けを事前に取得してくれます。 事前に取得ってよくわかりませんよね。 例をあげて考えてみましょう。 基本構文はこうです。 基本構文 # 関連名はアソシエーションの関連先 モデル名.inculudes(:関連名) controllers/posts_controller.rb class PostsController < ApplicationController def index # .allは省略できます @posts = Post.includes(:user) end end これで、ログを見てみましょう! User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" IN (?, ?, ?) [["id", 1], ["id", 2], ["id", 4]] このように、post.userに関するSQLは1行で完了しています。 つまりどういうことかというと、 Post.allの場合は、Postのデータを全て取得して、ビューのeach文で表示するときに、postのuser_idとどのユーザーが一致するか全てのユーザーの中から検証していました。 しかし、Post.includes(:user)の場合は、postsテーブルからデータを取得するときに、関連するusersテーブルのデータも取得しているので、each文で表示する時に、その都度SQLを発行する必要はなくなったのです。 まとめ N+1問題の対策としては、includesメソッドを使う! ポートフォリオ作成時に、N+1問題のことはなにも考えずにコーディングしていて、動作確認のときに「あれ?なんか重たいな」となったのが気づいたきっかけでした。 早いうちにN+1問題に触れられてよかったです。 ただ今回は自分なりに調べてみての結論で、他の記事の中では、includesメソッドを使う方法が推奨されていなかったりした記事がありました。 あとしょうがないのかもしれませんが、includesメソッドを使うことで、SQLの発行は改善されたのですが、コードの可読性がかなり下がるなと思いました。 まだまだ理解しきれていないことも多いので、これからもっとデータベースの知識を深めていきたいと思います!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Example title

Example
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】サンプルユーザーを増やす!Fakerの導入でサクラを作る方法

対象者 作成したサイトにテストユーザーを大量に導入したい方 目的 Gem「Faker」を使用してデータを増やすこと 実際の手順と実例 1.Fakerとは Fakerとは実際にいそうなユーザー名(ユーザー以外も行ける??)を作成するGemです。 これの導入によって手作業で1人ずつユーザー登録をしていくという作業や手間をカットできます。 2.Faker導入方法 1.gemに導入 : : gem 'rails', '6.0.3' gem 'bcrypt', '3.1.13' gem 'faker', '2.1.2' gem 'will_paginate', '3.1.8' : この後bundle installを実行します 2.サンプルユーザー作成 seedファイルに作成していきます。 まずメインとなるユーザーを1人作成します db/seed.rb User.create!(name: "Example User", email: "example@railstutorial.org", password: "foobar", password_confirmation: "foobar") 続いて、追加で偽物を何人作成するのか決めていきます。 db/seed.rb #上記と同じ User.create!(name: "Example User", email: "example@gmail.com", password: "foobar", password_confirmation: "foobar") #ここから追記 99.times do |n| name = Faker::Name.name email = "example-#{n+1}@gmail.com" password = "password" User.create!(name: name, email: email, password: password, password_confirmation: password) end これで完了です。ここでは99人のユーザーを作成しました。 この後、rails db:seedを実行すれば完了です。 ⚠先に何かデータが入っていいる場合、rails db:migrate:resetするといいかもしれません!また、サーバー起動中はrails db:migrate:resetがうまくできないこともあるそうなので、再起動して実行がおすすめです! 参照 Rails tutorial 10.3.2サンプルのユーザー 投稿者コメント Rails tutolialを進めてたら何やら面白そうなGemがあるなあとおもって記事にしました。 これからPF作成もあるので、使ってみようかなと思っています! My Profile プログラミング学習歴3ヶ月目のアカウントです! プログラミングスクールで学んだ内容や自分が躓いた箇所等のアウトプットの為に発信しています。 また、プログラミング初学者の方にわかりやすく、簡潔にまとめて情報共有できればと考えています。 もし、投稿した記事の中に誤り等ございましたら、コメント欄でご教授いただけると幸いです。 
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails deviseの導入方法と仕様・仕組み

deviseとは ユーザー管理機能の実装を補助してくれるRubyのgem(ライブラリ)です。 新規登録・ログイン・ログアウトやメール認証・SNS認証等の機能を実装でき、セキュリティ的にも安全なものが作れます。 devise導入 Railsのアプリケーションディレクトリ直下にあるGemfileの末尾に以下を追記します。 gem 'devise' ターミナルでRailsのアプリケーションディレクトリに移動し、以下コマンドを実行してインストールします。 bundle install # gemインストール rails g devise:install # deviseの設定ファイル生成 認証用のモデルを作成 認証用のモデルを作成します。以下ではuserモデルを作成していますがcustomerやmail_user、admin等好きなモデル名でOKです。 rails g devise user migrationファイルやmodelファイルが生成されます。 rails g model userとの違いは以下3点です。 migrationファイルにemailカラムやencrypted_passwordカラム等の記述が最初からされているものが生成される modelファイルにdevise :database_authenticatable, ~ ::validatableの記述が最初からされているものが生成される routes.rbにdevise_for :モデル名の記述が最初からされているものが生成される migrationファイルの編集・実行 migrationファイルを編集します。 必要に応じてnameカラム等追加したいカラムを追加します。 また以下機能のカラムを必要に応じてコメントアウト・アンコメントします。 機能 概要 デフォルト Recoverable パスワードリセット機能 有効 Rememberable ログイン状態を保持する機能 有効 Trackable ログイン回数や最終ログイン日時等の追跡をする機能 無効 Confirmable メール認証機能 無効 Lockable アカウントロック機能(指定回数連続で認証失敗するとアカウントをロックする機能) 無効 rails g db:migrateを実行してDBのテーブルを生成します。 コントローラーの作成 deviseのデフォルトの動作を改変する場合はrails g devise:controllers usersでコントローラーを作成します。 app/models/users/ディレクトリ以下に複数のコントローラーが生成されるので、必要なもの(改変したいコントローラー)のみroutes.rbに以下のように記述して読み込ませます。 routes.rb devise_for :users, controllers: { sessions: 'users/sessions' } ビューの生成 deviseのデフォルトのビューを改変する場合はrails g devise:views usersでビューを作成します。 app/views/users/ディレクトリ以下にビューファイルが生成されるので、改変したい箇所を編集します。 モデルの設定 modelファイルに記述されているdevise :database_authenticatable, ~ ::validatableを必要に応じて削除・追記します。以下各説明です。 これらの設定はdeviseのmodel作成コマンドではなく通常のrails g model ~コマンドで生成したモデルにも設定できます。 :database_authenticatable メールとパスワードを使った認証をしたい場合に設定します。 パスワード保存時に自動でハッシュ化してくれたり、ログイン・ログアウトのセッション管理もしてくれます。 これを設定したモデルにemailとencrypted_passwordカラムが無いとエラーになります。 routes.rbでdevise_forにこれを設定したモデルを指定すると、ログイン・ログアウト用のルーティングが設定されます。 session#new session#create session#destroy モデルにクラスメソッドやインスタンスメソッドを追加します。詳細は以下のドキュメントに記載されています。 https://www.rubydoc.info/github/plataformatec/devise/Devise/Models/DatabaseAuthenticatable :authenticatable メールとパスワードを使った認証以外の認証をしたい場合に設定します。 SNS認証用のモデルにはこちらを設定するのが良さそうです。 :database_authenticatableと異なり、ログイン・ログアウト用のルーティングは追加されません。 モデルにクラスメソッドやインスタンスメソッドを追加します。詳細は以下のドキュメントに記載されています。 https://www.rubydoc.info/github/plataformatec/devise/Devise/Models/Authenticatable :registerable 新規登録機能を実装したい場合に設定します。 SNS認証用のモデルには必要ありません。 routes.rbでdevise_forにこれを設定したモデルを指定すると、新規登録用のルーティングが設定されます。 registrations#cancel registrations#new registrations#edit registrations#update registrations#update registrations#destroy registrations#create :validatable メールとパスワードのバリデーションを追加します。 自分でバリデーションを設定する場合は必要ありません。 追加されるバリデーションは以下の通りです。 メールアドレスの入力が必須であり、有効な形式であり、一意であること(登録済みでないこと) 有効な形式は正規表現で/\A[^@\s]+@[^@\s]+\z/とされています。 @が1個含まれで、かつ、その前後に@とスペース以外の文字が1文字以上必要って意味...だと思います。 パスワードの入力が必須であり、文字数が6~128文字の範囲であり、パスワードと確認用パスワードが一致していること https://www.rubydoc.info/github/plataformatec/devise/Devise/Models/Validatable https://github.com/heartcombo/devise/blob/master/lib/devise.rb#L116 :confirmable メール認証機能を実装する場合に設定します。 routes.rbでdevise_forにこれを設定したモデルを指定すると、新規登録用のルーティングが設定されます。 confirmations#new confirmations#show confirmations#create アカウント登録時に認証用トークンを生成し、認証用トークンを付与した本登録用URLを記載したメールをユーザーに送信してくれます。 (confirmed_atが空の状態で保存されると、メールが送信されます。) これを利用する時はRailsの送信用メールサーバーの設定をする必要があります。 https://www.rubydoc.info/github/plataformatec/devise/Devise/Models/Confirmable https://github.com/heartcombo/devise/blob/master/lib/devise/models/confirmable.rb :omniauthable OAuth認証(SNS認証等)を実装する場合に設定します。 別途gemをインストールする必要があります。 routes.rbでdevise_forにこれを設定したモデルを指定すると、OAuth認証のコールバックURLのルーティングが設定されます。 :recoverable パスワードリセット機能を実装する場合に設定します。 :rememberable ログイン状態を保持する機能を実装する場合に設定します。 :lockable アカウントロック機能を実装する場合に設定します。 指定回数ログインに失敗するとアカウントをロックします。 アカウントロックの解除方法はメールでの解除・時間経過での解除の2つ用意されており、両方を設定することも可能です。 https://www.rubydoc.info/github/plataformatec/devise/Devise/Models/Lockable :timeoutable ログインセッションの有効期限機能を実装する場合に設定します。 設定された有効期限を過ぎるとログインページへリダイレクトされます。 https://www.rubydoc.info/github/plataformatec/devise/Devise/Models/Timeoutable :trackable ログイン回数やログイン日時・IPアドレスを記録する機能を実装する場合に設定します。 sign_in_count : ログイン回数 current_sign_in_at : 最終ログイン日時 last_sign_in_at : その前のログイン日時 current_sign_in_ip : 最終ログイン時のIPアドレス last_sign_in_ip : その前のログイン時のIPアドレス https://www.rubydoc.info/github/plataformatec/devise/Devise/Models/Trackable ルーティングの設定 devise_forやdevise_scopeでdeviseのルーティングを追加します。 複数の認証用モデルが存在する場合はそれぞれの認証用モデルに設定することが可能です。 devise_for :モデル名(複数形)ではそのモデルにdeviseメソッドで設定されてる内容を読み取ってそれに対応したルーティングを追加します。 deviseのデフォルトのコントローラーを改変する場合はコントローラーを指定します。 以下はセッション管理コントローラーと新規登録用コントローラーとメール認証のコントローラーを設定している例です。 routes.rb devise_for :users, controllers: { sessions: 'users/sessions', registrations: 'users/registrations', confirmations: 'users/confirmations' } 独自のルーティングを追加する場合はdevise_scopeを利用します。 こちらはdevise_scope :モデル名(単数形)にします。以下は例です。 routes.rb devise_scope :user do patch 'users/confirmation', to: 'users/confirmations#confirm' end deviseのヘルパーメソッド deviseは以下のような便利なヘルパーメソッドを用意してくれています。 以下userモデルの例です。user以外の名前のモデル名を付けている場合はメソッド名もモデル名に対応して変わります。 (adminモデルならadmin_sign_in?等) user_sign_in?: ユーザーがログインしているかtrue/falseで返します。 current_user: 現在ログイン中のユーザーのモデルインスタンスを返します。ログインしていなければnilを返します。 before_action :authenticate_user!: ログインしていなければログインページへ飛ばします。 ApplicationControllerまたは個別のコントローラーに設定します。 特定のページに設定したい場合はonlyやexceptオプションを利用します。 user_sign_in?メソッドは全てのコントローラー・ビュー内で利用できます。 current_userメソッドはdevise_forが呼び出された際に指定したモデル名に合わせて、そのdevise_forで設定されるコントローラーのアクション・及びそのビューでのみ利用できます。 ストロングパラメーター :database_authenticatableを設定しているモデルにカラムを追加した場合は以下のようにストロングパラメーターを設定します。 以下の例ではlast_nameカラムとfirst_nameカラムを設定しています。 user_details等の別のモデルに追加カラムを分離している場合は以下の設定は不要です。 application_controller.rb before_action :configure_permitted_parameters, if: :devise_controller? private def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_up, keys: [:last_name, :first_name]) end 参考 【Rails】deviseを導入してみる https://qiita.com/Hal_mai/items/350c400e8763ce0487a3 Rails deviseで使えるようになるヘルパーメソッド一覧s https://qiita.com/tobita0000/items/866de191635e6d74e392 【Rails】 deviseの使い方をマスターしてログイン認証機能を実装しよう! https://pikawaka.com/rails/devise Deviseのモヤモヤを解消して快適なRailsライフを送ろう! https://zenn.dev/kitabatake/articles/start-to-like-the-devise Document Module: Devise::Models https://www.rubydoc.info/github/plataformatec/devise/Devise/Models 最後に 間違い等あれば指摘いただけると幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails]パンくずリストの実装方法

はじめに パンくずリストを一ページごとに挿入するのは面倒で管理がしにくいです。webサービスに関しても遷移が多くなるので、パンくずリストを実装していないと希望のページに飛びにくくなってUI的に下がります。そこで、パンくずリストを簡単に導入できるGemを紹介します。是非つかっていただけたら記事を書いた甲斐があって嬉しいです。 紹介するGem gretel パンくずリストのためにつくられたGemで、スター数は少ないものの簡易的にパンくずリストを実装できます。 多少使いにくい部分も出てきましたので改善の余地があります。最新アップデートが一か月前なので、まだ期待はできるかなと。(自分でプルリク出すのはニッチすぎる部分なので控えます?) 使い方 1.Gemをインストール Gemfile gem "gretel" bundle install 2.Configファイルを作成 rails generate gretel:install 上記のコマンドを実行すると、config/breadcrumbs.rbが作成されます。このConfigファイルでパンくずリストのバックエンド部分を設定します。 3.Configファイルを編集 config/breadcrumbs.rb # rootの設定 crumb :root do link "Home", root_path end # 投稿一覧の設定 crumb :posts do link "投稿一覧", posts_path end # 投稿詳細の設定 crumb :post do |post| link post.title, post parent :posts # 投稿詳細の親元を投稿一覧に設定する end コードの説明 link: パンくずリストの実際に表示されるリンクの名前とpathを設定しています。投稿詳細の部分は、投稿のタイトルを表示しています。 crumb :example : くずを作成。exampleには変数名をつけています。view側で呼び出すときに、わかりやすい名前にしましょう。(基本的には、path名から取ってきます) parent: 親元のくず名を指定します。 4. Viewファイルに出力 layout/applcation.rb <%= breadcrumbs pretext: "You are here: ", separator: " &rsaquo; " %> <%= yield %> まず、表示する場所に挿入します。一定の場所に表示したいので例ではlayout/application.rbの<%= yield %>上に設置しています。 pretext : 現在位置のくずに追加でテキストを指定できます。 separator: 例えば、[Home > Posts > Post]の">"の部分を変数として決めれます。 views/posts/index.html.erb <% breadcrumb :posts %> 最後に作成した「くず」を呼び出してあげます。 これで完成です。 まとめ デメリットとしてはページごとに「くず」を呼び出さなければいけない部分であり、Configファイルでpathと連携することができれば各ページに挿入しなくて済むかなと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

部分テンプレートで初歩的なエラー

ActionView::MissingTemplate エラーが起きました! ポートフォリオが完成してきたので、可読性の向上、見た目を整えようと思ってheaderを部分テンプレートにしようと思い、取り組もうとコードを書き始めましたが・・・・。 結論 フォルダの階層を間違えておりました! お手本にしているのでは、sharedファイルは、viewファイルの階層にあったのですが、deviseを使っていた為、deviseファイルの階層(1階層下)に潜り込んでいたが故に怒ったエラーだったんですね。 反省点 エラーが出てググってみるも、同じエラーでも原因の種類もたくさんありました。 とりあえず今回は数分で気づくことができたので、自分の中ではよしとしましょう・・・。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【第9章】Railsチュートリアルでbcryptとfixtureについて忘れていたので復習した

Railsチュートリアル第9章(第6版)でbcryptとfixtureを忘れていたので、復習した。 ①bcrypt(ビー・クリプト)とは ・6.3.1 ハッシュ化されたパスワード にて登場 ・パスワードをハッシュ化する為の、最先端のハッシュ関数。 ・ハッシュ化すると元のデータを特定するのは、非常に難しい(ほぼ無理)。 ・bcryptアルゴリズムではハッシュ化する前にソルト化されたハッシュを追加している。 これにより、辞書攻撃やレインボーテーブル攻撃を防ぐことができる。 ②fixture(フィクスチャ)とは ・言葉自体は2.2 Usersリソース から登場している。 ・本格的に扱ったのは 8.2.4 レイアウトの変更をテストする ・テスト時に使用。 ・データベースに追加するテスト用データをfixtureで作成できる。 ・fixtureではERb(埋め込みRuby)を利用できる。 -fixtureの例- ---test/fixtures/users.yml--- abblepai: name: Abblepai Example email: applepai@example.com 以下のように参照できる。 user = users(:abblepai)  users=fixutreのファイル名、:abblepaiというシンボルはユーザーを参照するためのキー。 ③まとめ ①~②で忘れていた箇所を思い出せた。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Ruby] pryで、矢印キーを押すと`^[[A`などと出てしまう現象の解決法

環境 macOS 10.13.6 Ruby 2.5.7 Rails 6.1.3.1 Docker 20.10.7 Docker Compose v2.0.0-beta.6 現象 pryで矢印キーを押すと、次のような記号が現れてしまうようになってしまう。 例えば、矢印キーの↑を押すと、下記のような^[[Aという文字が表示されてしまいます。 その他、矢印キーの→を押すと^[[C、矢印キーの←を押すと^[[Bが表示されます。 原因 最近私はDockerのバージョンを20.10.7にUpgradeしたのだが、それに伴ってDocker Composeのバージョンがbeta版になってしまっていた。 つまりDocker Compose V2がデフォルトで有効になっていた。 これが、今回起きた矢印キーのバグの原因だった。 対処法 Docker Compose V2を無効にすると解決します。 docker docsに記載の通り、下記のように無効にします。 DockerDesktopを使用してDockerCompose V2を無効にするには: ① Dockerメニューから、[Preferences]> [experimental features]をクリックします。 ② [Use Docker Compose V2]チェックボックスをオフにします。 CLIを使用してDockerCompose V2を無効にするには、次のコマンドを実行します。 $ docker-compose disable-v2 参考記事
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む