20210514のRailsに関する記事は22件です。

Rails バリデーションの日本語化、レイアウト痔に起きた現象

某プログラミングスクールに通う転職生の、日々悩める日記 初めまして!某プログラミングスクールに通う転職生です。今回初投稿なのですが、投稿しようと思ったきっかけとしては エラーにイラつきすぎて、それを同じく初心者プログラマーの方に繰り返して欲しくないからです。 それでは初投稿、書いていきます!! 今回の現象 現象としては、Railsに入れたDeviseに、バリデーションを追加したのち、レイアウトと日本語を整えたいと思い 色々いじった後、Sign_up画面で何故かルーティングエラーが発生しました。 Sign_up画面のみです。更新ボタンや、その他のボタンを押しても発生します。 ちなみにLog_in画面やその他の画面では発生しません。 はぁぁん!!!???? 初めて出るエラーなので、本気でイラつきました笑 原因はなんなのか!とりあえず日本語化の文言を消してみたり 整えたレイアウトを元に戻したりしてみましたが、エラーは解消せず。 バリデーションエラーメッセージの日本語化は以下の記事を参考にしてください config/locales/models/ja.ymlの部分は、インデントに注意!! インデントで挙動が変わります。 結局の解決方法 Devise追加するとき、routes.rbにDeviseのルーティングって勝手に追加されますよね?? あれに僕は追加で以下の内容を変更を加えています。 routes.rb devise_for :users, :controllers => { //ここの右矢印から :sessions => 'users/sessions', :registrations => 'users/registrations', //ここまで } んで、さっきのエラーに、「ルーティングは上から順に読みます。」って書いてるのを翻訳に当てて思い出し 「あっ、そっか上から読むのか。んじゃあ新規登録(registration)の方が優先度高そうだから 描き直したらいけんじゃね???」と思って、順番を変えて以下のようにしました。 routes.rb devise_for :users, :controllers => { :registrations => 'users/registrations',  //下と入れ替えた :sessions => 'users/sessions', } するとあら不思議。エラー出ません!!!!!!!!!! やっぱ新規登録(registration)の方が優先度高いから、変にルーティングエラーかかってたのかな。。。。。。。。と思い、 イラつきは空の彼方に飛んで行きました。 初投稿に関して 今回初投稿ですが、同じ初心者プログラマーさんの役に立てばなぁと思います! もし間違って入ればご指摘ください! 以上です。ありがとうございました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails バリデーションの日本語化、レイアウト時に起きた現象

某プログラミングスクールに通う転職生の、日々悩める日記 初めまして!某プログラミングスクールに通う転職生です。今回初投稿なのですが、投稿しようと思ったきっかけとしては エラーにイラつきすぎて、それを同じく初心者プログラマーの方に繰り返して欲しくないからです。 それでは初投稿、書いていきます!! 今回の現象 現象としては、Railsに入れたDeviseに、バリデーションを追加したのち、レイアウトと日本語を整えたいと思い 色々いじった後、Sign_up画面で何故かルーティングエラーが発生しました。 Sign_up画面のみです。更新ボタンや、その他のボタンを押しても発生します。 ちなみにLog_in画面やその他の画面では発生しません。 はぁぁん!!!???? 初めて出るエラーなので、本気でイラつきました笑 原因はなんなのか!とりあえず日本語化の文言を消してみたり 整えたレイアウトを元に戻したりしてみましたが、エラーは解消せず。 バリデーションエラーメッセージの日本語化は以下の記事を参考にしてください config/locales/models/ja.ymlの部分は、インデントに注意!! インデントで挙動が変わります。 結局の解決方法 Devise追加するとき、routes.rbにDeviseのルーティングって勝手に追加されますよね?? あれに僕は追加で以下の内容を変更を加えています。 routes.rb devise_for :users, :controllers => { //ここの右矢印から :sessions => 'users/sessions', :registrations => 'users/registrations', //ここまで } んで、さっきのエラーに、「ルーティングは上から順に読みます。」って書いてるのを翻訳に当てて思い出し 「あっ、そっか上から読むのか。んじゃあ新規登録(registration)の方が優先度高そうだから 描き直したらいけんじゃね???」と思って、順番を変えて以下のようにしました。 routes.rb devise_for :users, :controllers => { :registrations => 'users/registrations',  //下と入れ替えた :sessions => 'users/sessions', } するとあら不思議。エラー出ません!!!!!!!!!! やっぱ新規登録(registration)の方が優先度高いから、変にルーティングエラーかかってたのかな。。。。。。。。と思い、 イラつきは空の彼方に飛んで行きました。 初投稿に関して 今回初投稿ですが、同じ初心者プログラマーさんの役に立てばなぁと思います! もし間違って入ればご指摘ください! 以上です。ありがとうございました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ストロングパラメーターで指定した情報だけ保存

はじめに 今回は学習中に作成した簡易版twitterでストロングパラメーターをアウトプットしていきます。 必要な情報だけをDBに保存していきます 仮に全てのデータ(パラメーター)を受け取る仕様の場合、悪意のあるパラメーターによって第三者にデータを改竄されてしまうなど、セキュリティ上に問題が起きてしまう恐れがあります。 回避するためには、ストロングパラメーターを使用して受け取るパラメーターを制限することが大切です。 実際にどんな情報が送られてきているか このアプリは写真のURLとつぶやきを投稿できるものです。 モデルやビュー等は割愛させていただき下記がコントローラーになります。 実際に投稿ボタンを押したら何が送られてくるのかbinding.pryで確認します。 tweet_controller.rb def new @tweet = Tweet.new end def create binding.pry #一度binding.pryで止めて中身を見るための記述 Tweet.create(tweet_params) end [1] pry(#<TweetsController>)> params => <ActionController::Parameters {"authenticity_token"=>"dGa9JyZphq/J2xJrdx7ZE47LlxWeBimigLTW5GgkU+MuYuCa/qDCnCJ3L5bdMCOVg+IfB+qyDnZdGa3sNHtEJw==", "tweet"=>{"image"=>"https://tech-master.s3.amazonaws.com/uploads/curriculums/images/Rails1-4/sample.jpg", "text"=>"スカイツリーが写った綺麗な景色!"}, "commit"=>"SEND", "controller"=>"tweets", "action"=>"create"} permitted: false> "tweet"の以下の{}に入っているデータだけ欲しいのですが、余計なものまで入っています。 image(写真のURL)とtext(つぶやき)だけのデータが欲しいのでここでストロングパラメーターを使います。 ストロングパラメーター 門番みたいな役割だと思っています。 「なんでも通すわけにはいかんぞ!!」 という感じで記述して許されたparamsしか通しません。 まずはrequireメソッド params.require(:モデル名) 必要とする情報を指定します。主にモデルを指定します。 今回では3行目に記述されているtweetです。 次にpermitメソッド params.require(:モデル名).permit(:キー名, :キー名) してしたキー名をDBに保存することを許可すると覚えます。 今回ではimageとtextを指定します。 params.require(:tweet).permit(:image, :text) このような形になります。 私が覚えやすいなと思った例えを紹介します。 まずはAmazonでイヤホンを頼んだとします。 家に商品届き、Amazonの箱の中に入っています。 その箱を開けるためにrequireメソッドで開封をし、今度はイヤホンの箱が入っています。 イヤホンの箱を開けるためにpermitで開けやっとイヤホン現物となります。笑 def create Tweet.create(tweet_params) end private def tweet_params params.require(:tweet).permit(:image, :text) end end tweet_paramsというストロングパラメーターを定義し、createメソッドの引数に使用して、tweetsテーブルへ保存できます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

system_specでjqueryをテストする

導入 前回の記事で、:rack_test → :seluniumの以降が成功し、無事jqueryなどのDOM操作をrspecでテストできるようになった、わけではありませんでした。 今回はこちらの記事を参考に、正式にDOM操作をrspecでテストできるようになりました。(ありがとうございました!) 結論 結論としましては、前回の記事の設定でDOM操作をテストする為には、以下の3操作が必要でした。 chromedriverのDockerイメージを導入する Dockerfile テスト実行環境をchromedriverに設定 ← 前回の記事の内容 system_spec.rbでjs: trueにする 補足:自分の場合はポート番号が重複するエラーが発生したので(多分そう)、テスト環境のポート番号を変更しました。 rails_helper.rb Dockerfile RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \ && curl -sL https://deb.nodesource.com/setup_10.x | bash - \ && apt-get install -y nodejs \ && mkdir /myapp +RUN apt-get update && apt-get install -y unzip && \ + CHROME_DRIVER_VERSION=`curl -sS chromedriver.storage.googleapis.com/LATEST_RELEASE` && \ + wget -N http://chromedriver.storage.googleapis.com/$CHROME_DRIVER_VERSION/chromedriver_linux64.zip -P ~/ && \ + unzip ~/chromedriver_linux64.zip -d ~/ && \ + rm ~/chromedriver_linux64.zip && \ + chown root:root ~/chromedriver && \ + chmod 755 ~/chromedriver && \ + mv ~/chromedriver /usr/bin/chromedriver && \ + sh -c 'wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -' && \ + sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list' && \ + apt-get update && apt-get install -y google-chrome-stable WORKDIR /myapp COPY Gemfile /myapp/Gemfile COPY Gemfile.lock /myapp/Gemfile.lock rails_helper.rb RSpec.configure do |config| config.before(:each, type: :system, js: true) do driven_by :remote_chrome Capybara.server_host = IPSocket.getaddress(Socket.gethostname) - Capybara.server_port = 3000 + Capybara.server_port = 3010 Capybara.app_host = "http://#{Capybara.server_host}:#{Capybara.server_port}" end config.include FactoryBot::Syntax::Methods spec/system/site_layouts_spec.rb require 'rails_helper' -RSpec.describe 'Layouts', type: :system do +RSpec.describe 'Layouts', js: true, type: :system do let(:user) { create(:user) } context "user signed in" do : expect(page).to have_link href: notifications_path expect(page).to have_selector "i.fa-bell" expect(page).to have_link href: search_works_path, class: "fa-search" + within("li.dropdown") do + expect(page).to have_link class: "dropdown-toggle" + click_on "#{user.username}" + end expect(page).to have_link "ログアウト", href: destroy_user_session_path expect(page).to have_link "プロフィール", href: user_path(user) expect(page).to have_link "アカウント編集", href: edit_user_registration_path おわりに 最後まで目を通して頂きありがとうございました! ただ、正直まだ全然理解が追いついていなくて恥ずかしいくらいです。将来的には、もっと根本的な理解ができているようなエンジニアになりたい。(本当に
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

コントローラーへ送る値を同じ値を複数指定

コントローラーへ送る値を同じ値を複数指定 選択したユーザーの情報をparamsで扱えるようにパラメーターを送ります。 以下のようにnew.html.erbを編集してください。 app/views/rooms/new.html.erb <!-- 中略 --> <select name="room[user_ids][]"> <option value="">チャットするユーザーを選択してください</option> <% User.where.not(id: current_user.id).each do |user| %> <option value=<%= user.id %>><%= user.name %></option> <% end %> </select> <!-- 中略 --> select要素のname属性にroom[user_ids][]を指定し、option要素のvalue属性にuser.idを指定しました。このように記述することで、これまでとは異なる形でパラメーターが送信されるため、paramsは以下のようになります。 【例】paramsの中身 # room[user_ids][ ]で送られるパラメーター {"room" => {"user_ids" => ["選択したユーザーのid"]}} この記述について、name属性のroom[user_ids][]を、room[user_ids]と[]に分けて説明します。 まず、room[user_ids]という記述は、キーに対する値という通常のパラメーターと異なり、値としてさらにハッシュを入れ子にすることを示すものです。 【例】room[user_ids]で送られるparamsの中身 {"room" => {"user_ids" => "値"}} 続いて、末尾についた[]について説明します。この記述は、キーに対する値を配列として格納することを示すものです。これにより、1つのキーに対して、複数の値を受け取ることができるようになります。 【例】room[user_ids][]で送られるparamsの中身 {"room" => {"user_ids" => ["値"]}} 以上の仕組みを利用して、選択したユーザーの情報をコントローラーへ送信する仕組みができました。 しかし、現状の実装のままでは、現在ログインしているユーザーのidを送信することができず、送信したユーザーのみチャットルームに存在していることになってしまいます。 したがって、現在ログイン中のユーザーのidも一緒に、paramsでコントローラーへ送信できるよう実装します。 パラメーターにログイン中ユーザーのidも含めましょう 以下のようにnew.html.erbを記述してください。 app/views/rooms/new.html.erb <!-- 中略 --> <select name="room[user_ids][]"> <option value="">チャットするユーザーを選択してください</option> <% User.where.not(id: current_user.id).each do |user| %> <option value=<%=user.id%>><%= user.name %></option> <% end %> </select> <input name="room[user_ids][]" type="hidden" value=<%= current_user.id %>> <!-- 中略 --> この記述で、現在ログイン中のユーザーが持つidをparamsに含めることができます。 【例】 <input name="room[user_ids][]" type="hidden" value=<%= current_user.id %>> type属性にhiddenを指定することで、画面上には表示されないinput要素を作成できます。そして、先ほどのselect要素と同様、name属性にroom[user_ids][]を指定し、room[user_ids]をキーに対する値を配列で受け取る仕組みです。value属性にはcurrent_user.idを指定しているため、room[user_ids]キーに対して、ログイン中ユーザーのidを配列として格納し、コントローラーへ送信します。 この記述の結果、コントローラーに送られるparamsは以下のようになります。 【例】room[user_ids][]で送られるparamsの中身 {"room" => {"user_ids" => ["選択したユーザーのid", "現在ログインしているユーザーのid"]}} room[user_ids]に2種類のユーザーidを格納することができました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Deviseのデフォルトのメールアドレスバリデーションが弱すぎる件に対処する

Railsでユーザのログイン機能を実装する場合、言わずと知れた Devise を使うといろんな機能がすぐに使えて便利ですよね。デフォルトでは、メールアドレスとパスワードで登録・ログインするようになっていますが、今更ながら不正なメールアドレスが登録されてしまうというバグを生み出してしまいました Deviseにおけるメールアドレスのバリデーションには、 $ bin/rails g devise:install で生成される config/initializers/devise.rb に定義されている正規表現が使われるのですが… /\A[^@\s]+@[^@\s]+\z/ うーん、弱い! ということで、今回は email_validator というGemを使って、メールアドレスの有効性をある程度きちんと検証できるようにしていきます。 email_validatorをインストール Gemfileにemail_validatorを追記し、インストールします。 Gemfile gem 'email_validator' bundle install Deviseの設定を書き換える config/initializers/devise.rb に定義されている正規表現を、email_validatorが提供している正規表現に書き換えます。 email_validatorも、デフォルト(Loose mode)の正規表現はDeviseと同様に /\A[^\s]+@[^\s]+\z/ となっているので、Strict modeかRFC modeの正規表現を使うようにしましょう。RFCに準拠すると、メールアドレスでよく使われている文字が使えないことがあるので、今回はStrict modeを使うことにします。 config/initializers/devise.rb - config.email_regexp = /\A[^@\s]+@[^@\s]+\z/ + config.email_regexp = EmailValidator.regexp(mode: :strict) これで、メールアドレスの有効性をある程度きちんと検証できるようになりました 最後に 今回は、mode: :strict と明示的にStrict modeを使うように指定しましたが、Gemfileに Gemfile gem 'email_validator', require: 'email_validator/strict' のように記述することで、デフォルトをStrict modeにすることもできます。 Railsは便利なGemが多く、盲目的に使うと思わぬバグや脆弱性を仕込んでしまう可能性があります。注意して使いたいですね(自分への戒め
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

お気に入り機能の実装

目次 1.はじめに 2.いいねボタンの導入 3.同期通信で実装する 4.非同期通信で実装する 5.おわりに 1. はじめに 今回は同期通信で実装した後、それをもとに非同期通信に切り替えていきます。まずは必要なものを導入しましょう。 2. いいねボタンの導入 font-awesome-railsを導入しましょう。もし文字をクリックしてお気に入り機能を実装する場合であれば3.同期通信で実装するから実装していただいて問題ないです。以下のようにアイコンをクリックしてお気に入りをつけたり外したりしたい場合はこちらを参考にしてください。 1. GEMの導入 gemfile gem 'font-awesome-rails' *導入したら必ずbundle installしてください。 2. CSSファイルに記述を追加する app/assets/stylesheets/application.css *= require font-awesome これで使う準備はOKです。 3. 使用したいビューファイルに記述を追加する ビューファイル <i class="fa fa-アイコン名" aria-hidden="true"></i> どんなアイコンを使用するかはご自由に!! ここをクリック!から探してね!! 3. 同期通信で実装する アプリケーション作成、ユーザー登録、投稿機能ができている体で進みます。そこまでは自力で実装してください。 1. お気に入り機能に必要なものを揃える まずは必要なもの...そうですコントローラーとモデルですね! どんな名前でもいいので作成してください。今回この記事ではlikeという名前で実装してます。 2. ルーティングの設定 今回は投稿機能に関連する機能のため、ネスト構造で設定します。今回はお気に入りをつけて外すだけなのでcreateとdestroyのみ記述してます。 routes.rb Rails.application.routes.draw do #(省略) resources :posts do resources :likes, only: [:create, :destroy] end end 3. モデルの設定 まず、マイグレーションファイルにはuser_idとpost_idが保存できるように設定してマイグレートしておいてください。 今回1人のユーザーはお気に入りを何回もすることができます。また、投稿された物に対してもたくさんお気に入りすることができます。 そのため以下のようにアソシエーションを設定します。 app/models/like.rb class Like < ApplicationRecord belongs_to :user belongs_to :post end app/models/user.rb #以下を追加する has_many :likes app/models/post.rb #以下を追加する has_many :likes 4. コントローラーの設定 まずはお気に入りを登録するcreateアクションの設定です。 今回は投稿したpostに対して行いたいためまずはどのpostなのかを取得する必要があります。その後、そのpostに対してお気に入りを新しく作り、保存ができたらトップページに戻るように設定します。 お気に入りの削除は今の考え方で、保存ではなく削除したら...の場合で記述しましょう。 以下のようになります。 likes_controller.rb class LikesController < ApplicationController  before_action :set_post def create @like = Like.new(user_id: current_user.id, post_id: params[:post_id]) @like.save redirect_to root_path end def destroy @like = current_user.likes.find_by(post_id: @post.id) @like.destroy redirect_to root_path end private def set_post @post = Post.find(params[:post_id]) end end 5. ビューファイルの設定 お気に入り機能だけを別に切り出したいので今回私は部分テンプレートに記述しました。そのため、元々の記述の部分は以下のようになります。 views/posts/index.html.erb #(省略) <div class="likes_heart" id="post_<%= post.id %>"> <%= render "likes/like", post: post %> </div> 部分テンプレートでは、以下の条件をつけました。 ・ログインしていないとお気に入りできない ・1投稿に対して1回しかお気に入りができない(既にお気に入りに登録していたら削除するボタンになる) likes/_like.html.erb <% if user_signed_in? %> <% if post.liked_by?(current_user) %> <%=link_to post_likes_path(post), method: :delete do%> <i class="fa fa-heart" aria-hidden="true" id="heart"></i> <%= post.likes.count %> <% end %> <% else %> <%=link_to post_likes_path(post), method: :post do%> <i class="fa fa-heart" aria-hidden="true" id="heart"></i> <%= post.likes.count %> <% end %> <% end%> <% end %> また、今回liked_byというメソッドを使用します。whereメソッドを使用し、likesテーブルに「user_id」が存在しているかどうか検索をかけています。(存在すれば削除、存在しなければお気に入り追加、と振り分ける) app/models/post.rb #省略 def liked_by?(user) likes.where(user_id: user.id).exists? end 同期通信はこれで終わり!!!実際に動かしてみてください!! 4. 非同期通信で実装する ここが本当に難しい...と感じました!もう少し!頑張りましょう!! 1. コントローラーの修正 非同期通信に変更するのでトップページに遷移させる記述を削除しましょう。 以下のようになります。 likes_controller.rb class LikesController < ApplicationController before_action :set_post def create @like = Like.new(user_id: current_user.id, post_id: params[:post_id]) @like.save end def destroy @like = current_user.likes.find_by(post_id: @post.id) @like.destroy end private def set_post @post = Post.find(params[:post_id]) end end 2. ビューファイルの設定 「remote: true」を付与します。付与することで、パラメーターがHTML形式ではなくJS形式で送られるようになります。 今回の場合は「remote: true」をlink_toメソッドに付与することで、likes_controller.rbのcreateアクション後は、views/likes/create.js.erbが呼び出されるようになります。 views/likes/_like.html.erb <% if user_signed_in? %> <% if post.liked_by?(current_user) %> <%=link_to post_likes_path(post), method: :delete,remote: true do%> <i class="fa fa-heart" aria-hidden="true"></i> <%= post.likes.count %> <% end %> <% else %> <%#link_to post_likes_path(post), method: :post do%> <%= link_to post_likes_path(post), method: :post, remote: true do%> <i class="fa fa-heart" aria-hidden="true"></i> <%= post.likes.count %> <% end %> <% end%> <% end %> 3. js.erbファイルの作成 今回は2つ用意しましょう。 記述は以下です。 views/likes/create.js.erb document.getElementById('post_<%= @post.id %>').innerHTML = '<%= j(render 'like' ,post: @post) %>' views/likes/destroy.js.erb document.getElementById('post_<%= @post.id %>').innerHTML = '<%= j(render 'like' ,post: @post) %>' 詳しくみていきましょう。 まずはこちらです。 document.getElementById('post_<%= @post.id %>') 書き換えたいビューのIDを取得しています。 IDに関しては、3.同期通信で実装するの5.ビューファイルの設定で設定してますので確認してください。 '<%= j(render 'like' ,post: @post) %>' 部分テンプレートの内容に置き換えることを表してます。 今回使用した部分テンプレートは_like.html.erbなのでこのような書き方です。部分テンプレートに保存/削除した内容を渡さないといけないので、部分テンプレート内で使用している変数post: @postを記述してます。 5. おわりに 普通にJSファイルを作成して行うやり方もあると思います。皆さんがしっくりくるやり方で実装してみてください!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

$ bundle exec rake db:migrate RAILS_ENV=production時のエラーに関して

はじめに 作成したアプリをAWSにデプロイしようと作業しており、「$ bundle exec rake db:migrate RAILS_ENV=productionコマンドを入力した際に発生したエラーを解決するまでの道のりです。 同じエラー内容が出ている方の一助になれれば幸いです。 エラー解決に向けて unicornをインストールして、「$ bundle exec rake db:migrate RAILS_ENV=production」コマンドを入力すると、 ec2-user@ip-10-0-0-42 アプリ名]$ bundle exec rake db:migrate RAILS_ENV=production rake aborted! ActiveRecord::AdapterNotSpecified: 'production' database is not configured. Available: ["default", "development", "test"] とエラー表示がされました。 どうも'production' databaseに問題がありそうです。そこでdatabase.ymlを確認してみます。 config/database.yml 〜省略〜 production: <<: *default database: <%= Rails.application.credentials.db[:database] %> username: <%= Rails.application.credentials.db[:username] %> password: <%= Rails.application.credentials.db[:password] %> socket: <%= Rails.application.credentials.db[:socket] %> production databaseあるじゃん!と思い、別の要因を探っていました。 しかし原因はymlファイルのインデントの付け方にありました。 正しくは以下のようになります。 config/database.yml 〜省略〜 production: <<: *default database: <%= Rails.application.credentials.db[:database] %> username: <%= Rails.application.credentials.db[:username] %> password: <%= Rails.application.credentials.db[:password] %> socket: <%= Rails.application.credentials.db[:socket] %> ここでの注意点は、インデントはタブではなく、半角スペースを指定してあげてください。 もしここが上手くいっていないと、「Please note that YAML must be consistently indented using spaces. Tabs are not allowed. 」とエラーになってしまいます。 これで再度「bundle exec rake db:load_config RAILS_ENV=production」コマンドを入力したところ、またエラー表示が…。 == 20210320002528 CreateItems: migrating ====================================== -- create_table(:items) rake aborted! StandardError: An error has occurred, all later migrations canceled: Mysql2::Error: Failed to open the referenced table 'categories': CREATE TABLE `items` (`id` bigint NOT NULL AUTO_INCREMENT PRIMARY KEY, `name` varchar(255), `image` varchar(255), `category_id` bigint, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, INDEX `index_items_on_category_id` (`category_id`), CONSTRAINT `fk_rails_89fb86dc8b` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ) /var/www/rails/men-skincare/db/migrate/20210320002528_create_items.rb:3:in `change' /home/ec2-user/.rbenv/versions/2.5.3/bin/bundle:23:in `load' /home/ec2-user/.rbenv/versions/2.5.3/bin/bundle:23:in `<main>' Caused by: ActiveRecord::StatementInvalid: Mysql2::Error: Failed to open the referenced table 'categories': CREATE TABLE `items` (`id` bigint NOT NULL AUTO_INCREMENT PRIMARY KEY, `name` varchar(255), `image` varchar(255), `category_id` bigint, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, INDEX `index_items_on_category_id` (`category_id`), CONSTRAINT `fk_rails_89fb86dc8b` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ) /var/www/rails/men-skincare/db/migrate/20210320002528_create_items.rb:3:in `change' /home/ec2-user/.rbenv/versions/2.5.3/bin/bundle:23:in `load' /home/ec2-user/.rbenv/versions/2.5.3/bin/bundle:23:in `<main>' Caused by: Mysql2::Error: Failed to open the referenced table 'categories' /var/www/rails/men-skincare/db/migrate/20210320002528_create_items.rb:3:in `change' /home/ec2-user/.rbenv/versions/2.5.3/bin/bundle:23:in `load' /home/ec2-user/.rbenv/versions/2.5.3/bin/bundle:23:in `<main>' Tasks: TOP => db:migrate (See full trace by running task with --trace) うーん、itemsテーブルの作成時にエラーが発生しているようです。 もっと詳しくエラー内容を確認してみると、itemsテーブルを作ろうとしている時に、categoriesテーブルの参照がないよと言われています。 itemsテーブルとcategoriesテーブルの作成順番がうまくいっていないようなので、一度categoryモデルごと削除、再度マイグレーションして、無事エラー解消することができました。 終わりに ymlファイルのインデント規約に関しては知らなかったので良い勉強となりました。 もっとLinuxの知識をつける必要があると感じました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[rails] DateTime#agoがRails5.2まで1.dayといった引数を受け付けていたが6.0からダメになった原因を調べた

Rails6.0への更新中、理由が不明だった為調べました # DateTime#agoの実装 def ago(seconds) since(-seconds) end # rails 5.2 DateTime.current => Fri, 14 May 2021 16:20:00 +0900 DateTime.current.ago(1.day) => Thu, 13 May 2021 16:14:26 +0900 # rails 6.0 DateTime.current => Fri, 14 May 2021 16:31:41 +0900 DateTime.current.ago(1.day) TypeError: not an integer from /bundle/gems/activesupport-6.0.3.7/lib/active_support/core_ext/date_time/calculations.rb:113:in `Rational' 5.2ではagoで呼ばれているDateTime#sinceの実装で、agoの引数をroundしてintegerとなっていたのが、roundしなくなりRationalの引数として不適切になったから出たエラーのようです。 PRを見た感じ、昔はroundをする意味があったが今は無いのでしなくなったという事かな? そもそも、secondsを要求されているので1.dayといった値を渡していたのがおかしくて、たまたまroundされていただけで意図しない使い方していた気がする...! 素直にこう書いておきます DateTime.current - 1.day => Thu, 13 May 2021 16:34:06 +0900 修正PR 5.2 実装 6.0 実装
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】カラム型の種類

カラム型の種類 データ型 種類 string 文字列(1〜255文字) text 長い文字列(1〜4,294,967,296文字) integer 整数(4バイト) bigint 整数(8バイト) float 浮動小数 decimal 精度の高い小数 numeric 数値 datetime 日時 time 時刻 date 日付 binary バイナリデータ timestamp タイムスタンプ boolean 真偽値型 primary_key プライマリーキー(主キー) references 他のテーブルへの外部キーの定義、_id が付いた整数
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails ユーザー登録機能を一瞬で作ろう

見てくださりありがとうございます。 自分は独学でrailsを勉強しているものです。 railsでWEBアプリケーションを作っているとユーザー登録の作成は必ず行いますよね! なので今回はユーザー登録機能を実装するまでに必要なコードを淡々と書いて、コピペするだけでユーザー登録機能が作成できるようにします 前提 アプリはすでに作成されている状態を想定しています(rails new アプリ名) 今回のユーザー登録機能とはユーザー登録画面でユーザーを新規登録するまでであり、登録内容の修正、ユーザー削除等の機能は作りません あくまでもユーザー新規登録機能を作成し、成功すればユーザー詳細画面に飛ぶだけです 登録情報は名前とメールアドレスだけにしておきます ユーザーコントローラーの作成 コマンド rails generate controller Users show new ユーザーモデルの作成 コマンド rails generate model User name:string email:string ルートの作成 config/routes.rb Rails.application.routes.draw do resources :users end ユーザーコントローラーのアクションの作成 コマンド class UsersController < ApplicationController def show @user = User.find_by(params[:id]) end def new @user = User.new end def create @user = User.new(user_params) if @user.save redirect_to @user else render 'new' end end private def user_params params.require(:user).permit(:name, :email) end end createアクションに@user = User.new(user_params)このような記述がありますが、 実は@user = User.new(params[:user]) このようにも記述できます。 しかし後者はセキュリティー上良くありません。理由は後者の記述だと悪意のあるユーザーにでアプリケーションのデータベースが書き換えらる可能性があるからです。 今回で言うとname,email以外の例えばadminという値をリクエストに紛れ込ませ、管理者権限を奪い取ることができてしまいます。 ですのでuser_paramsによってnameとemail以外はリクエストの対象にならないように制限をかけることが正しい記述方法になります redirect_to @user は redirect_to user_url(@user)と等価になります これはユーザー作成が成功し、データベースへの保存が完了したらユーザー詳細ページに飛ぶことを示しています ユーザー登録画面の作成 app/views/users/new.html.erb <h1>ユーザー登録</h1> <%= form_with(model: @user, local: true) do |f| %> <%= f.label :name %> <%= f.text_field :name %> <%= f.label :email %> <%= f.email_field :email %> <%= f.submit "新規ユーザー登録", class: "btn btn-primary" %> <% end %> ユーザー登録画面の作成(簡素ですが許して下さい) app/views/users/show.html.erb <h1>ユーザー詳細ページ</h1> <p><%= @user.name %>,<%= @user.email %></p> 以上これだけの記述でユーザー登録が完成します。 登録内容にパスワードが必要だったり、ユーザー情報の編集、ユーザーの削除機能が追加されても簡単に少ない記述で多くの機能が作成できるのがrailsのいいところですよね! 見てくださりありがとうございました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】実務未経験の僕が共同開発に参加して学んだこと

0. はじめに はじめまして! この記事では、「実務未経験の私が Rails 共同開発に挑戦し、そこで学んだことや躓いたこと、反省した点」などについてまとめています。 チームでの開発現場経験を積むことで、「コミュニケーションの適切な取り方」や「わからない部分の質問の仕方」、「コンフリクトの解消の仕方」など、一人での学習では決して学ぶことのできない貴重な経験を積ませていただくことができました。 今回はそのような共同開発の現場で実際に学んだことをまとめて、今後の自分の成長につなげることができたらなと考えております! 自己紹介                                           まずは簡単な自己紹介からさせて頂きます! スペック 24歳 エンジニアを目指している駆け出しエンジニア 学習中の言語:Ruby, Ruby on Rails 今後学習予定の言語や知識:Javascrict, AWS HTML・CSS・Sass・も出来ます。 趣味 勉強 : 好きでやっているので、もう趣味ですw 読書 : 一番好きな本は、SF小説、「千九八四年」です。 TVゲーム : 最近は勉強のため封印中。スマブラしたい。 もうちょっとコロナが落ち着いたら、旅行を趣味に加えたいです。 性格 割と慎重派だと思います。前職で絶対にダブルチェックを欠かさなかったです。 温厚だと思ってます。怒った記憶がない。怒りは無駄だと考えてます。 2. 今回の共同開発に参加しようと思った動機 まず、「なぜ今回の共同開発に参加しようと思ったのか?」の根本的な動機の部分を述べさせて頂きます。端的に言うと、以下のものを「得たい!」と思ったので、共同開発に参加させて頂きました。 コミュニケーションスキルの向上 チームでの開発経験 問題にぶち当たった時に自分で原因を特定し、解決を図るための「自走力」 試行錯誤した上でどうしてもわからない場合、素直に質問できる柔軟性 これらのものを「共同開発」に参加することを通して獲得したいなと思いました。 結果的に、特に「コミュニケーション」の部分に関してはスキルの向上ができたのと、以前よりもより自信を持つことができた気がします。 ここについての具体的なやり取りに関しては後述させて頂きます! 3. Rails 共同開発で取り組んだ内容 共同開発で取り組んだ内容を簡単にご説明していきます! 成果物 今回の共同開発では「ECサイト」の購入者視点の画面の実装に取り組みました。 概要 開発期間:5/1 ~ 6/ 30(2ヶ月間) 週1回のチームミーティングを行い、進捗状況の確認を行う 週2~3回の作業会を行い、それぞれわからないところを質問し合う 構成メンバー 講師・TA:現役エンジニア2名 共同開発メンバー:未経験2名, 現役インターン生1名 使用した言語・技術 バックエンド Ruby(バージョン:2.7.1) Ruby on Rails(バージョン:6.0.3.5) フロントエンド HTML5 CSS3 Bootstrap(5.0.0.beta2) インフラ Docker docker-compose データベース MySQL2(0.5.3) 使用したツール・環境 Slack:レビュー依頼、進捗状況の確認、日報の共有などをしました。 GitHub:タスク管理・確認、プルリクエストを出す、コードレビューを受ける、受けた指摘に対応し、コミットを出すなどをしました。 Googleドライブ:モックアップ、基本設計(ER図/画面遷移図)、画面定義書などのファイルを管理・共有のために使用しました。 Git / Sourcetree:コミットやプッシュなどの git 操作をするために利用しました。 DeepL:英語対策のための翻訳アプリ 使用したエディター:Visual Studio Code 使用したPC:Mac ER図 実装した(する予定)機能 新規ユーザ登録機能 ログイン / ログアウト処理 商品検索 商品詳細へ カートへ カートを開く 購入確定 Top画面に戻る 履歴を開く 注文検索 注文キャンセル ユーザ情報を開く ユーザ情報修正 / 退会処理 修正確定 4. Rails 共同開発で僕が担当した箇所 ①products 関連の DB構築 ER図を見て、必要なカラムや属性を考え、migrationファイルを作成しました。 ↓こういった感じのmigrateファイルを作成 class CreateUsers < ActiveRecord::Migration[6.0] def change create_table :users do |t| t.string :password, limit: 64 t.string :last_name, limit: 16 t.string :first_name, limit: 16 t.string :zipcode, limit: 16 t.string :prefecture, limit: 16 t.string :municipality, limit: 16 t.string :address, limit: 16 t.string :apartments, limit: 32 t.string :email, limit: 128 t.string :phone_number, limit: 16 t.references :user_classification, null: false, foreign_key: true t.string :company_name, limit: 128 t.boolean :delete_flag t.timestamps end end end ②products 関連の seedファイル作成 seeds.rb を記述。 別Qiitaにメモしました。 ③users 関連の validate作成 models/users.rb にvalidateをかけました 別Qiitaにメモしました。 ④商品詳細画面 を作成 商品名・カテゴリ・商品説明・値段 をDBから引っ張ってきて表示するように実装しました。 ⑤商品詳細画面(存在しないID) を作成 存在しない商品が指定された際には、この画面が出てくるように、 if分岐させました。 ⑥ユーザー情報更新画面 を作成 ユーザー情報の更新を行う画面の見た目とroutes を作成しました。 <%= form_with %>, <form.label>, <form.text_fiels> を使用して作成しています。 ⑦ユーザー情報更新機能 を実装 ⑥で見た目を実装し、ここで実際の動作を実装しました。 flashを利用したアラートを採用し、更新成功時には、user詳細画面にとび、「更新に成功しました」というメッセージを、失敗時には、user情報更新画面にrenderして、「更新に失敗しました」というメッセージを表示するように実装しています。 ※今後も実装完了次第、追加していきます! 5. 【必ず身に付けておきたい】 講師に学んだプルリクエストの出し方 共同開発では、開発業務以外にも Git や GitHub の操作方法がとても学びになりましたが、その中でも特に「 Pull Request(プルリクエスト )の出し方」が個人的には参考になりました! 今後の開発を進めていく上での基礎として、必ず身に付けておきたいと思いました。 ▼ プルリクエストを出す際の雛形となるテンプレート 以下は講師が提供してくださったテンプレートを元に僕が作成したプルリクエストの一例です。 プルリクエスト出す際は、以下のようなフォーマットをもとに作成しています。 プルリクエストの最終的な確認項目 このプルリクエストで実行したこと(概要) 対象 issue 重点的に見て欲しいところ(不安なところ) 実装できなくて後回しにしたところ チェックリスト(動作確認・ rubocop の実行など) その他の参考情報(参考にした記事のリンクなど) このようなフォーマットを元に書くことによって、レビュアーの方にとってわかりやすいプルリクエストの作成に繋がると感じました。 特に「重点的に見て欲しいところ(不安なところ)」の項目では、「問題に躓いた時にうまく人に頼れるスキル」も大事になって来ると思うので、不安だったことについては小さなことであっても、必ず書くようにしました。 ▼ 1指摘1コミット また、コードレビューを受ける際は「1指摘1コミット」でやり取りをするようにしました。つまり、複数の指摘を同時に受けたとしても、対応する際は一つずつコミットを出して個別に対応していくということ。 これは講師の方から「意外と知らない人が多いけど、大事なこと」として教わりました。 以下のような感じです↓ 基本的なことかもしれませんが、だからこそ、この機会で知ることができた意義は大きい!と考えています。 6. Rails 共同開発で躓いた点・大変だったこと 共同開発において躓いたことや大変だったこと、またそれに対する僕の対応です! 主に、以下の2点でつまずきました。 ① コンフリクトの発生 ※ 追加あるかもです。(無いことを願うw) ① コンフリクトの発生 コンフリクト発生に関しては、共同開発が始まった初っ端から躓いてしまい、かなり焦りました? しかし、練習段階で失敗することに意味があるんだろう。 と考え、自分を奮い立たせて対処しました。 何度か、コンフリクトを発生させているうちに、 「あぁ、多分、ここが原因だろ、一回、developをmergeして…。よし!」 ぐらいの気軽さで対処できるようになりました。 Gitの基礎は抑えられたのでは? と考えています。 7. Rails 共同開発に参加する経緯&身についたこと 2021年2月頃までは僕は主に一人でプログラミング学習に取り組んでいました。 しかし、エンジニアなるためには、実務に近い、チーム単位での経験が必要なのではないか、お互いの進捗状況を確認しあったり、わからないことを相談しあったりするなどと言った「協調性」が必ず必要になってくるのではないかと考えていました。 今回の共同開発で、早めにそのスキルを身につけておくことによって、技術的なサポートをして頂く際の「質問力」であったり、スムーズやりとりを行うための「コミュニケーション能力」の面においては、他の未経験者よりも前に立てたのではないか、と考えています。 この経験は、これからエンジニアになっていく上で、この上なく大事な経験だと思っていますし、この経験があれば、きっとエンジニアになれる!という自信にも繋がりました。 技術的にまだまだ未熟な自覚はあります。 しかし、それ以外の、エンジニアにとって大切な、「協調性」を身につけられたという点において、この共同開発への参加はとても有意義だったなぁ。と感じています。 8. さいごに【まとめ】 ここは、共同開発終了後に書こうと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

新method追加2

searchアクションのルーティングを設定しよう 今回はsearchという命名で、7つの基本アクション以外のアクションを定義します。 collectionとmemberを学習します。 collectionとmember collectionとmemberは、ルーティングを設定する際に使用できます。 これを使用すると、生成されるルーティングのURLと実行されるコントローラーを任意にカスタムできます。 collectionはルーティングに:idがつかない、memberは:idがつくという違いがあります。 1つずつ使用例を見ていきましょう。 【例】collectionで定義した場合 Rails.application.routes.draw do resources :tweets do collection do get 'search' end end end 【例】collectionのルーティング Prefix Verb URI Pattern search_tweets GET /tweets/search(.:format) tweets#search ルーティングに:idが付いていないことがわかります。 続いてmemberの場合を見てみましょう。 【例】memberで定義した場合 Rails.application.routes.draw do resources :tweets do member do get 'search' end end end 【例】memberのルーティング Prefix Verb URI Pattern search_tweet GET /tweets/:id/search(.:format) tweets#search URLの指定先が、collectionは:idなし、memberが:idありとなっていることが確認できますね。 今回の検索機能の場合、詳細ページのような:idを指定して特定のページにいく必要がないため、collectionを使用してルーティングを設定しましょう。 routes.rbを以下のように編集します。 config/routes.rb Rails.application.routes.draw do devise_for :users root to: 'tweets#index' resources :tweets do resources :comments, only: :create collection do get 'search' end end resources :users, only: :show end
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

has_secure_password とは(rails)

has_secure_passwordは簡単に言ったらユーザー登録やログインの時に出てくるパスワード入力に関するrailsのメソッドです。 has_secure_passwordを用いることで少ないコードでパスワードを安全に保管できるようにしてくれたり、ユーザー登録画面によくある、パスワード、確認パスワードなども作成できるようになります 今回はそのhas_secure_passwordについてしっかりまとめていきたいと思います。 has_secure_passwordの使用方法 app/models/user.rb class User < ApplicationRecord ・ ・省略 ・ has_secure_password end has_secure_passwordでできること has_secure_passwordを用いると主に3つのことが可能になります ①セキュアにハッシュ化したパスワードを、データベース内のpassword_digestという属性に保存できるようになる。 ②2つのペアの仮想的な属性(passwordとpassword_confirmation)が使えるようになる。 ③authenticateメソッドが使えるようになる(引数の文字列がパスワードと一致するとUserオブジェクトを、間違っているとfalseを返すメソッド) ①セキュアにハッシュ化したパスワードを、データベース内のpassword_digestという属性に保存できるようになる。 入力したパスワードをそのままデータベースに保存するのはセキュリティー上良くありません。 そのためhas_secure_passwordを用いてハッシュ化といういわゆる暗号化を行い暗号化した状態でデータベースに保存します。 そしてログインするときなどにパスワードを入力すると思いますがそのパスワードもハッシュ化され、ハッシュ化されたパスワード同士を比べることでパスワードがあっているかどうかを確認します。 ハッシュ化にはさまざまなハッシュ関数が使われますが僕は'bcrypt'を使っています 下記のようにGemfileファイルに追加して使用します Gemfile gem 'bcrypt','3.1.13' ②2つのペアの仮想的な属性(passwordとpassword_confirmation)が使えるようになる。 has_secure_passwordを使うには1つ条件があり、それはモデル内にpassword_digestという属性が含まれていることです。(password,password_confirmation属性はhas_secure_passwordを用いることで自動に仮想的に作成され、フォームにも利用できるのでモデルで明示的に作成する必要はありません) 例えば、ユーザー登録に名前、メールアドレス、パスワードが必要ならば下記のコードをコマンドに記述すれば良いです コマンド rails generate model User name:string email:string password_digest:string このようにモデルにpassword_digest属性を追加することによってhas_secure_passwordメソッドが使えるようになり、仮想的な属性(passwordとpassword_confirmation)もフォームで使えるようになります 以下に使用例を記述します app/view/shared/form.html.erb <%= form_with(model: @user, local: true) do |f| %> <%= f.label :name %> <%= f.text_field :name %> <%= f.label :email %> <%= f.email_field :email %> <%= f.label :password %> <%= f.password_field :password %> <%= f.label :password_confirmation, "Confirmation" %> <%= f.password_field :password_confirmation %> <%= f.submit "Create my account", class: "btn btn-primary" %> <% end %> 少し難しい記述はありますが、まず@userでユーザーモデルを元にフォームが作られていることがわかります。 そして、name,email,password, password_confirmationがフォームで使用されていることがわかります。 password_confirmationはモデルで明示的に記述していませんが、password_digestを追加することとhas_secure_passwordを記述することによって仮想的に作成され、使用できるようになっています ③authenticateメソッドが使えるようになる authenticateメソッドは非常に簡単で、authenticateメソッドの引数の文字列をハッシュ化した値と、データベース内にあるpassword_digestカラムの値を比較します。 その結果が同じならばTrue、違っていたらFalseを返します railsconsole >> User.create(name: "Michael Jordan", email: "Jordan@example.com", ?> password: "Michael", password_confirmation: "Michael") >> user.authenticate("not_the_right_password") false >> user.authenticate("Michael") True
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】ユーザー管理機能(devise)の導入

目的 Railsで作成したアプリにユーザー管理機能を追加する。 開発環境 macOS: Big Sur Rubyバージョン: 2.5.1 Railsバージョン: 6.0.0 前提 アプリが作成されている。 アプリ名はtest-appとする。 手順 そもそもdeviseとは Gemのインストール deviseの設定ファイルを作成 deviseのUserモデルを作成 テーブルを作成 deviseのビューファイルを作成 usersテーブルにカラムを追加 deviseにストロングパラメーターを設定 そもそもdeviseとは ユーザー管理機能を実装するためのGemの事です。 deviseを導入することにより、簡単にユーザー管理機能を実装することができます。 Gemのインストール それでは早速deviseをインストールしていきましょう! まずGemfileに下記のようにdeviseを追記します。 Gemfile # 中略 gem 'devise' その後、ターミナルでGemをインストールします。 ターミナル % bundle install インストール後はサーバーを再起動することを忘れずに! インストールしたGemが反映されるタイミングはサーバー起動時のため、下記コマンドで再起動しましょう! ターミナル % rails s これでdeviseがインストールできたはずです。 deviseの設定ファイルを作成 次に設定関連に使用するファイルを生成します。 deviseを使用するためには、 専用のコマンドで設定ファイルを作成する必要があるので注意してください。 ターミナル % rails g devise:install コマンドを実行すれば設定ファイルが作成されるので、次へ進みましょう! deviseのUserモデルを作成 deviseを使用する際には、deviseで認証するためのUserモデルを新しく作成する必要があります。 作成にはdeviseのモデル作成用コマンドでUserモデルを作成します! ターミナル % rails g devise user この際に、ユーザーに関するモデルやマイグレーションも自動生成されています。 また、routes.rbに以下のルーティングが自動的に追記されます。 config/routes.rb Rails.application.routes.draw do devise_for :users end テーブルを作成 先ほど自動生成されたマイグレーションファイルを使用して、テーブルを作成します。 db/migrate/20XXXXXXXXX_devise_create_users.rb class DeviseCreateUsers < ActiveRecord::Migration[6.0] def change create_table :users do |t| ## Database authenticatable t.string :email, null: false, default: "" t.string :encrypted_password, null: false, default: "" ## Recoverable t.string :reset_password_token t.datetime :reset_password_sent_at ## Rememberable t.datetime :remember_created_at # 省略 t.timestamps null: false end add_index :users, :email, unique: true add_index :users, :reset_password_token, unique: true # add_index :users, :confirmation_token, unique: true # add_index :users, :unlock_token, unique: true end end マイグレーションファイルを確認すると、すでにメールアドレスとパスワードのカラムを作成する記述があります。 他のカラムを追加する場合はこのタイミングで追記します。(今回はひとまずこのまま進めます!) テーブルの設計を確認した後、下記コマンドでマイグレーションを実行しましょう! ターミナル % rails db:migrate これで、usersテーブルが作成されました! テーブル・カラム情報を変更したため、サーバーを再起動してください。 ターミナル % rails s これでhttp://localhost:3000へアクセスしても問題なく動作します。 deviseのビューファイルを作成 deviseでログイン機能を実装すると、ログイン/サインアップ画面が自動的に生成されますがビューファイルとしては生成されません。 これは、deviseのGem内に存在するビューファイルを読み込んでいるためです。 このままではビューファイルを編集できないため、deviseのコマンドを利用して、ビューファイルを生成します。 ターミナル % rails g devise:views このコマンドはdevise内のビューファイルをコピーし、app/viewsの配下に配置してくれるコマンドです。 これでビューファイルの編集が可能になります! 以上で一通りdeviseの導入はできましたが、現状メールアドレスとパスワードのカラムしか存在していません。 ユーザー名など他にも保存したいデータを追加したい場合の方法も合わせて記載します! usersテーブルにカラムを追加 まずはテーブルにカラムを追加するために、マイグレーションを生成します! 今回はユーザー名のカラムを追加していきます。 ターミナル % rails g migration AddNameToUsers name:string % rails db:migrate 作成済みのテーブル内容を変更する際にはrails g migrationコマンドを使用します! このコマンドは、指定するファイルの名前によって、どのようなテーブル操作を行うかを自動で記述してくれます。 rails g migration Addカラム名To追加先テーブル名 追加するカラム名:型とすることで、 テーブルに必要なコードが記述された状態で、マイグレーションが生成されます。 サーバーの再起動も忘れずに行いましょう! ターミナル % rails s これでユーザー名のカラムが追加されました! deviseにストロングパラメーターを設定 次にdeviseにストロングパラメーターを設定していきます! 今回は新規登録時の処理に対して、nameというキーのパラメーターを新たに許可します。 ここで注意点ですが、deviseにストロングパラメーターを設定するときは特別な記述が必要です。 それは、deviseの処理を行うコントローラーがGem内に記述されており、編集することができない為です。 そのため、編集可能なapplication_controller.rbにストロングパラメーターを定義しておき、その処理を読み込ませます! app/controllers/application_controller.rb class ApplicationController < ActionController::Base before_action :configure_permitted_parameters, if: :devise_controller? private def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_up, keys: [:name]) end end devise_parameter_sanitizerメソッドを使用し、deviseで設定されているsign_up(新規登録処理)のリクエストからパラメーターを取得しています。 devise_parameter_sanitizerメソッドとはdeviseにおけるparamsのようなメソッドです。 このメソッドとpermitメソッドを組み合わせることにより、新しく追加したカラムもストロングパラメーターに含めることができます! ちなみにconfigure_permitted_parametersというメソッド名ですが、 deviseの提供元でこのメソッド名を紹介していることから、慣習的に同名で定義することが多いようです! 最後に 長かったですが、これでログイン機能は導入できたと思います! あとは各自ビューファイルなど編集してください。 では。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsにおけるnew, build, save, createの違い

new インスタンスをメモリ上に作成する。 user = User.new(name: "Mike") build newのエイリアス。 newと全く同じ動作をする。 save メモリ上に存在するインスタンスをデータベースに保存する。 user = User.new(name: "Mike") user.save create newとsaveをまとめて実行する。 user = User.create(name: "Mike")
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[初心者向け]SystemSpecの基本的な使い方とサポートモジュールについて

はじめに 初めまして、takumi(@takumi73)と申します。 今回、RspecのSystemSpecについて学習したので、簡単ではありますが、基本的な使い方についてまとめていこうと思います。 内容に誤りがありましたら、ご指摘頂けると嬉しいです。 SystemSpecでできること 従来の統合テストはFeatureSpecであり、それをより便利かつスピーディーに開発できるようにしたものがSystemSpecになる。 利点としては以下が挙げられる ・ブラウザ上で実行することがデフォルトで可能になった統合(E2E)テスト ・エラー発生時スクリーンショットで画面を確認できる 環境 capyrbaraとfactory_botを使用しています。 ruby 2.6.3 Rails 6.1.3.2 factory_bot 6.1.0 factory_bot_rails 6.1.0 capybara 3.35.3 SystemSpecの基本的な使い方 ※事前準備に関してはわかりやすい記事がたくさんあるので今回は省略させて戴きます。 【Rails】はじめてのSystemSpec(RSpec) 基本的な書き方は以下の通りになり、今回はログインを例に挙げています。 ※わかりやすくするためにあえてdescrideなどは記述していません。 [spec/system/users_spec.rb] require 'rails_helper' RSpec.describe 'Users', type: :system do it '入力が全て正しい時、ログイン完了のフラッシュが表示されていること' do visit login_path fill_in 'email', with: @user.email fill_in 'password', with: @user.password click_button 'ログイン' expect(page).to have_content 'ログインしました!' end end これでログインが正常に完了することのテストができます。 visitでテストしたいパスに移動する fill_in 'email'でname属性を指定し、with:で、入力値を再現できます。 <input type="email" name="email" class="form-control" value="<%= @email %>"> click_button 'ログイン'でログインというボタンタグを実行。 <button type="submit" class="btn btn-primary">ログイン</button> ・リンク(aタグ)の場合は、click_link ・どちらか気にせずクリックを実装したいときはclick_on ・値が存在せずアイコンなどの場合は、find('.クラス名').clickでクラス名を指定する   expect(page).to have_content 'ログインしました!'の部分が、実行結果の期待する振舞いを書く。 今回であれば、ログインが成功した場合成功のフラッシュが表示されるようになっているのでそれを検証しました。 再現に少し苦労したもの 画像アップロードの実装 attach_file 'image_icon', 'app/assets/images/default.jpeg' 画像アップロードを再現するには、attach_fileを使用します。 <%= form.file_field :image_icon %> image_iconには、属性が入ります。 'app/assets/images/default.jpeg'で、再現に使用する画像のパスを指定します。 SystemSpecの便利な機能 スクリーンショット テストを実行しエラーが発生すると、実行後の画面をスクリーンショットしてくれる。 [Screenshot Image]:~と表示されるのでその後のURLをブラウザで表示させることができる。 テストのデバック うまくテストが通らない場合に、テストが失敗する時の画面を確認する方法があります。 スクリーンショット機能と似ていて、テストが失敗するであろう箇所の画面を確認することができる。 1gem 'launchy'をインストール 2デバックしたい箇所にsave_and_open_pageに追記する。 visit login_path fill_in 'email', with: @user.email fill_in 'password', with: @user.password save_and_open_page click_button 'ログイン' expect(page).to have_content 'ログインしました!' この場合、入力値が再現できているかなどを確認することができる。 エラーが発生していなくても、入力値の確認など利用することもできる。 DRYなテストにする方法(サポートモジュール) コードの重複を減らす方法として、サポートモジュールを使用する方法がある。 ※他にも方法はある。 サポートモジュール 特性としては、重複しているワークフローをモジュール化し、DRYなコードを実現することができる。 方法 ①有効化 spec/rails_helper.rbの以下の記述をコメント解除 Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f } ②ファイルの作成 spec/support/任意のモジュール名_support.rbを作成 ③モジュールの作成 先ほどのログイン実装部分をlogin_un_as(user)というメソッドで定義。 module LoginSupport def login_in_as(user) visit login_path fill_in 'email', with: @user.email fill_in 'password', with: @user.password click_button 'ログイン' end end RSpec.configure do |config| config.include LoginSupport end ④書き換え login_in_as @user expect(page).to have_content 'ログインしました' 先ほど記述していた行を削除し、login_in_as @userで呼び出すことができる。 これでかなりスッキリした記述にすることができる。 また、loginの実装は、何度も使用することがあるため、この1行で実装できるのはかなり便利。 まとめ ・SystemSpecを使用することで、アプリケーションの一連の流れをテストすることができる。 ・処理が複雑になってくるため、必要に応じてDRYなコードを意識する必要がある。 最後まで読んでいただきありがとうございました! 参考文献 rspec-rails 3.7の新機能!System Specを使ってみた RSpec公式 【Rails】はじめてのSystemSpec(RSpec)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Herokuを使用したデプロイの方法

Heroku CLIをインストール 下記のコマンドを実行するとherokuというコマンドが使用できるようになり、ターミナルからHerokuへアクセス可能になります。 % brew tap heroku/brew && brew install heroku インストールが完了したら下記のコマンドを実行してバージョンを確認します。 % heroku --version heroku/7.40.0 darwin-x64 node-v12.16.2 上記のようにバージョンが出力されれば成功です。(バージョンの値は実際と異なる場合があります。) Herokuにログイン 下記のコマンドを実行し、メールアドレスとパスワードを入力します。 % heroku login --interactive Heroku上にアプリケーションを作成 下記のコマンドを実行。 % heroku create アプリ名 下記のコマンドを実行し、正しく設定できたことを確認 % git config --list | grep heroku Heroku上でMySQLを使えるように設定 下記のコマンド実行でデーターベースをMySQLに設定します。 % heroku addons:add cleardb Ruby on Railsを使う場合は、MySQLに対応するGemについて考慮する必要があり、そちらの設定もします。 まず、ClearDBデータベースのURLを変数heroku_cleardbに格納するため下記のコマンドを実行します。 % heroku_cleardb=`heroku config:get CLEARDB_DATABASE_URL` 続いて、データベースのURLを再設定するため下記のコマンドを実行します。 % heroku config:set DATABASE_URL=mysql2${heroku_cleardb:5} Heroku上にマスターキーを設定 Heroku上に環境変数を設定します。下記のコマンドを実行。 % heroku config:set RAILS_MASTER_KEY=`cat config/master.key` 設定が正しくできているか、Herokuの環境変数一覧を表示。 % heroku config Herokuで利用する環境を指定 Rubyのバージョン2.6.5が動作するStackを指定しました。下記を実行。(注:ダウングレードは極力避けた方が良いそうです。) % heroku stack:set heroku-18 -a アプリ名 Herokuへアプリケーションを追加 Gitで管理しているリポジトリをHerokuに反映させます。下記のコマンドを実行。 % git push heroku master Heroku上でマイグレーションファイルを実行 % heroku run rails db:migrate 公開を確認 下記のコマンドを実行すると公開されたアプリケーションの詳細を見ることができます。 % heroku apps:info 表示されたURLへアクセスすると、公開されたページを見ることができます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【rails】衝撃!form_with では、value が要らない。

初期値の設定にvalue を書かなくて良い! rails の form_withにて、value を書かなくて良いことをさっき知ったので、記録を残しておこうと思います。 記述例 <%= form_with(model: @user, local: true) do |form| %> <h2 class="text-center mt-5">ユーザ情報修正</h2> <table width="60%" style="margin: auto;"> <tr height="40"> <td align="center">氏名</td> <td> <%= form.label :last_name, "姓" %> <%= form.text_field :last_name %> <%= form.label :first_name, "名" %> <%= form.text_field :first_name %> </td> </tr>   <% end %> これで画面表示すると、初期値が表示されました。 form_with 内の、model: @user属性。 ここで、@user に中身が入っていると、form_value は空気を読んで、初期値を入れ込んでくれます。 便利! 情報更新画面とか作るときに、もうvalue を設定する必要ありません。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Nuxt.js & RailsでGoogle OAuthをしてみる

概要 Nuxt.jsをフロントエンド、Railsをバックエンドに使ったwebアプリにGoogleのOauthを実装します! 前提としてログイン認証はフロントエンドで行い、バックエンドにはトークンを送ってトークン認証を行います 作業環境 Nuxt.js: 2.14.6 SPA Ruby on Rails: 6.0.2.2 APIモード 準備 実装を始める前にGCPに新しくプロジェクトを作成します APIとサービス > 認証情報 と進みOAuthクライアントIDを作成します OAuthクライアントIDを作成しようとするとOAuth同意画面の作成を求められるので、 こちらも作っちゃいます! OAuth同意画面 User Type 外部: Gsuiteを使わない 内部: Gsuiteを使う アプリケーション名 なんでも良い サポートメール なんでも良い スコープ email profile openid OAuthクライアントID 承認済みの JavaScript 生成元 http://localhost:3333 承認済みのリダイレクト URI http://localhost:3333/login http://localhost:3333/login/callback OAuthクライアントIDを作成するとクライアントIDが発行されるのでこれをメモっておきます GCPのプロジェクト作成はこれで完了です! Nuxt.jsへの実装 次にフロントエンドの認証実装をします 今回はNuxtのauth moduleを使ってサクッと実装します @nuxtjs/auth インストール auth moduleですが、 V4が@nuxtjs/authでV5が@nuxtjs/auth-nextとなっているので注意です! 公式のドキュメントもV5を対象にしているみたいなので、 最新の@nuxtjs/auth-nextを導入します $ yarn add @nuxtjs/auth-next Typescriptの場合はtsconfigのtypesに追記 tsconfig.json "compilerOptions": { "types": [ "@nuxtjs/auth-next" ] } @nuxtjs/auth セットアップ nuxt.config.jsに設定を追記します 注意して頂きたいのは@nuxtjs/auth-nextの設定で、 トークンはデフォルトではJWTトークンにはならないので、 以下のような設定にする必要がありました 細かい設定については公式の方に詳しく解説されています! nuxt.config.js // 全てのページで認証を適用する router: { middleware: ['auth'] }, // module modules: [ '@nuxtjs/axios', '@nuxtjs/dotenv', '@nuxtjs/auth-next' ], // @nuxtjs/auth-nextの設定 auth: { redirect: { login: '/login', logout: '/login', callback: '/login/callback', home: '/' }, strategies: { google: { clientId: process.env.GOOGLE_CLIENT_ID, responseType: "token id_token", codeChallengeMethod: '', autoLogout: true, token: { property: 'id_token', type: 'Bearer', maxAge: 1800 }, endpoints: { userInfo: undefined, }, }, }, }, 使い方 すごいざっくり説明すると this.$auth.loginWith('google')でログイン this.$auth.logout()でログアウト ユーザーデータはstoreに入る!です! <script lang="ts"> import Vue from 'vue' export default Vue.extend({ // 認証をなしにしたい場合はこのように記述 // auth: false, layout: 'blank', methods: { // 認証フォームを開く login(): void { this.$auth.loginWith('google') }, // ログアウトする logout(): void { this.$auth.logout() }, }, }) </script> this.$auth.loginWith('google')で 以下のようなログインフォームに遷移します ログインが成功するとstoreのauthに以下のようなフォーマットで保存されます auth:Object loggedIn:true strategy:"" user:Object email:"" email_verified:true family_name:"" given_name:"" hd:"" locale:"" name:"" picture:"" sub:"" 通常のvuexと同じように参照できます $store.state.auth.loggedIn # これでも可能 $auth.loggedIn トークン管理 cookieを確認してみるとしっかりトークンが入っているのが確認できます こちらが未ログイン時 こちらがログイン時 JWTトークンというのはそれぞれ有効期限があり、 もちろん有効期限が切れてしまうとトークンでの認証ができなくなってしまいます 有効期限がきたら自動で更新したいところなんですが、 OauthのJWTトークンは更新ができない・・・?みたいなので断念 Nuxtの実装はこれで完了です! フロントだけのアプリであればこれだけで認証実装完了ですね! Railsへの認証実装 最後にバックエンドの実装をします! 初めにaxiosでapi通信をした際にトークン情報が送られてきているか確認してみます railsでrequestのヘッダーを見てみます cookieにあった物と同じBearerトークンが送られてきているか確認します request.headers['Authorization'] JWTトークンをデコードしてくれるサービスがあるので、 こちらも使ってトークンがしっかり送られてきているか確認すると良いです! (Bearer%20部分は除いてください) google-id-token インストール tokenの認証にはgoogle-id-tokenというgemを使用します bundle install以外に特にやる事はないです Gemfile gem 'google-id-token' トークンを認証する authenticate_or_request_with_http_tokenはリクエストヘッダーからtokenを取り出す処理です include ActionController::HttpAuthentication::Token::ControllerMethodsの記述が必要になります validator.check(token, ENV['GOOGLE_CLIENT_ID'])でtoken認証を行う事ができて、 トークンのデコードデータが戻り値となっています。 トークンが不正であったり、期限切れの場合GoogleIDToken::ValidationErrorにキャッチされます class AuthenticationController < ActionController::API include ActionController::HttpAuthentication::Token::ControllerMethods def authenticate authenticate_or_request_with_http_token do |token, _options| validator = GoogleIDToken::Validator.new validator.check(token, ENV['GOOGLE_CLIENT_ID']) rescue GoogleIDToken::ValidationError => e p e end end end 最後に これにてNuxt.js & RailsでGoogle OAuthを行う実装は終わりです! 二つのライブラリで簡単にOAuthの認証を実装する事ができました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

草野球の出欠確認Webアプリを作ろう! part.6

これから作っていく簡単なWebアプリの作成メモ(自分の備忘)です。 自分用なのであまり凝りすぎないように書いていきたい。 <<前回の記事 ※前回導入していたRspecですが、なぜかchromedriverが動作しなくて原因も不明だったので、いったんTDDは凍結とします(そのままずっと凍結の可能性も...)。 今回やったこと スケジュールの編集 schedulesコントローラーのeditとupdateのアクションを整える。 app/controllers/schedules_controller.rb def edit @schedules = Schedule.find(params[:id]) end def update @schedules = Schedule.find(params[:id]) if @schedules.update(schedules_params) redirect_to schedule_path(@schedules), notice: "予定を編集しました。" else render :edit end end viewのほうも整える。 views/schedules/edit.html.erb <h1>予定の編集</h1> <div class="row_line"> <%= link_to '予定一覧へ', schedules_path, class: 'btn primary-btn' %> </div> <%= form_for @schedules, url: {action: "update", id: @schedules.id} do |f| %> <div class="row_line"> <label>件名:</label> <%= f.text_field :title %> </div> <div class="row_line"> <label>予定の日付:</label> <%= raw sprintf( f.date_select(:date_of, use_month_numbers: true, order: [:year,:month,:day], selected: Time.zone.now, start_year: Time.zone.now.year + 5, end_year: Time.zone.now.year, date_separator: '%s' ),'年','月') + '日' %> </div> <div class="row_line"> <label>開始時間:</label> <%= f.time_select :start_time %> &nbsp;~&nbsp; <label>終了時間:</label> <%= f.time_select :end_time %> &nbsp;( <label>集合時間:</label> <%= f.time_select :meeting_time %> ) </div> <div class="row_line"> <%= f.submit "保存する" %> </div> <% end %> スケジュールの編集画面に遷移できないと動作確認できないので、遷移できるようにしておく。 以下の記事を参考にした。 【jQuery】HTMLのtableの行にリンクを設定する Rails6でjQueryの導入方法 $ yarn add jquery config/webpacker/environment.js const { environment } = require('@rails/webpacker') const webpack = require('webpack') environment.plugins.prepend('Provide', new webpack.ProvidePlugin({ $: 'jquery/src/jquery', jQuery: 'jquery/src/jquery' }) ) module.exports = environment app/javascript/packs/application.js (略) import "jquery" (略) ※jqueryを導入した際にrailsサーバーを起動中だったら、一度サーバーを停止して再度起動しなおすほうがよい(過去バージョンでの経験則) jqueryを使えるようにした後は、そのjqueryを使用して一覧画面のテーブルの1行をクリックしたときに、編集画面に遷移するように準備する。 views/schedules/index.html.erb (略) <tbody> <% @schedules.each do |lst| %> <tr class="clickable-row" data-href="<%= edit_schedule_path lst.id %>"> <td><%= lst.title %></td> <td><%= lst.date_of %></td> <td><%= lst.start_time.strftime('%H:%M') %> ~ <%= lst.end_time.strftime('%H:%M') %></td> </tr> <% end %> </tbody> (略) 以下のjsファイルを新規に作成した。 app/javascript/packs/schedules.js $(function($) { $(".clickable-row").css("cursor","pointer").click(function() { location.href = $(this).data("href"); }); }); 作成したjsファイルを読み込むようにする。 (各モデルの名前付きのjsはもっと個別機能の処理を記述するほうが良いのではと思ったのは、ファイルを作成してからだった。今後余裕があればリファクタリングできるといいポイント。) views/layouts/application.html.erb (略) <head> <title>YaQue</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' %> <%= javascript_pack_tag 'schedules', 'data-turbolinks-track': 'reload' %> </head> (略) ↓テーブルの行をクリックすると以下のようになる。 Railsの5.2あたりとJqueryの導入方法がすこし違って戸惑った。 今回はここまで。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【rails】テキストエディターの実装(summernote)

実装すること ・gem summernoteを使用して、投稿フォームをテキストエディターにする。 ・テキストエディターでリンクや画像の投稿も簡単。 公式: https://summernote.org/ Github: https://github.com/summernote/summernote-rails 参考記事 ①https://bagelee.com/programming/rails-wysiwyg-gem/ 完成形 ・ 見た事があるテキストエディターが表示され、投稿詳細にも反映されています。 ・ 他にも画像の添付、文字の太さの変更など機能様々。 前提 下記の機能実装済み。 ・ devise機能(今回は、memberモデル) ・ 投稿機能(今回は、questionモデル) shema.rb ActiveRecord::Schema.define(version: 2021_05_05_122222) do create_table "members", force: :cascade do |t| t.string "email", default: "", null: false t.string "encrypted_password", default: "", null: false t.datetime "remember_created_at" t.string "name", default: "", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["email"], name: "index_members_on_email", unique: true"index_members_on_reset_password_token", unique: true end create_table "questions", force: :cascade do |t| t.integer "member_id", null: false t.string "title", default: "", null: false t.text "content", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["member_id"], name: "index_questions_on_member_id" end end 手順 ①gem"summernote"のインストール ②assetsのcss/scss + jsファイルへの追記 ③summernote-init.coffeeの作成 ④viewへの記載① ⑤viewへの記載② 実装 1. gem"summernote"のインストール gemをインストールします。 ただ、githubを見る限り、summernote+他のGemも同時にインストールします。 もし、既にインストールしているものがあれば、それを除いたものをインストールしましょう。 simple_formに関しては、 viewの書き方で使うか使わないかなので、「viewへの記載」をインストールするか判断してください。 Gemfile gem 'jquery-rails' gem 'bootstrap', '~> 4.5' gem 'simple_form' gem 'summernote-rails', '~> 0.8.9' terminal $ bundle install 2. assetsのcss/scss + jsファイルへの追記 それぞれによって異なりますが、 application.css/scssファイル と jsファイルに下記を追加します。 @importは、外部のcssファイルを読み込む際に使う記述です。 下記のscssファイルにおいては、 "summernote-bs4.css"というcssファイルを読み込むようにしています。 assets/stylesheets/application.scss *= require social-share-button *= require_tree . *= require_self */ @import "bootstrap"; @import "summernote-bs4"; application.jsも同様に読み込ませます。 assets/stylesheets/application.js //= require jquery3 //= require popper //= require bootstrap-sprockets //= require rails-ujs //= require summernote/summernote-bs4.min //= require summernote-init //= require activestorage //= require turbolinks //= require_tree . //= require social-share-button 3. summernote-init.coffeeの作成 先ほど下記を記載したかと思います。 //= require summernote-init "summernote-init"のファイルは現状ない為、これから作成します。 これによってviewにテキストエディターを表示したり、カスタマイズしたりできます。 assets/javascripts/summernote-init.coffee $(document).on 'turbolinks:load', -> $('[data-provider="summernote"]').each -> $(this).summernote placeholder:"質問したい内容を記入しよう。一番見て欲しい箇所は色をつけるなどで強調してみよう!" height: 300 4. viewへの記載 ① 先ほどsummernote-init.coffeeを機能させるには、下記をviewに記載する必要があります。 assets/javascripts/summernote-init.coffee [data-provider="summernote"] なので、text_areaの中に記述します。、 questions/new.html.erb(抜粋) <div class="form-group"> <p class="font-weight-bold"><%= f.label :質問内容 %></p> <p><%= f.text_area :content, class:"form-control w-100", 'data-provider': :summernote %></p> </div> これによってcoffeeファイル(js)がその箇所と連動し、表示されます。 新規投稿画面にテキストエディターが表示されたかと思います。 【こちらは全文です。】 questions/new.html.erb <%= form_with model: @question, local: true do |f| %> <%= render "layouts/error_messages", resource: @question %> <div class="form-group"> <p class="font-weight-bold"><%= f.label :質問タイトル %></p> <%= f.text_field :title, placeholder: "タイトルを記入しましょう。(5〜50文字以内)", class:"form-control w-100" %> </div> <div class="form-group"> <p class="font-weight-bold"><%= f.label :タグ %>(0個からいくつでも選択可能です。)</p> <p><%= f.collection_check_boxes :tag_ids, Tag.all, :id, :name, class:"form-control", prompt:"この中からタグを1つ選んでください。", mutiple: true %></p> </div> <div class="form-group"> <p class="font-weight-bold"><%= f.label :質問内容 %></p> <p><%= f.text_area :content, class:"form-control w-100", 'data-provider': :summernote %></p> </div> <div class="form-action"> <%= f.submit "質問する", class:"btn btn-success w-100" %> </div> <% end %> 5. viewへの記載 ② 最後にテキストエディターで投稿した文字の表示設定をします。 今のままでは、画像のようにタグが表示されているかと思います. これを正しく表示させるための記述を投稿詳細のviewに手を加えます。 解決策: https://qiita.com/iwamot/items/74c2bd9ebd3ac6458837 記事に書いてるエスケープ処理を使います。 questions/new.html.erb <div class="questions-content offset-md-2"> <h4><%== question.content %></h4> </div> 通常:  <%= %> 今回:  <%== %> と = を2つつけます。 これによってview側での表示がテキストエディターでの文字設定が反映されます。 これで基本的にsummernoteは実装できたかと思います!! 補足:原因不明のエラーに関して 無事実装でき、最初は表示されていたのですが、 突然表示されなかったり、エラーが出て動かなくなる。などがありました。 もしかしたらこれを参考にした方も同じ事が起きるかも??しれません、、、、。 これに関して正直、なぜ起きたのか原因はわからずでした、、。 解決策としては、summernote.js をassetsファイルに格納したところ動きました。 参考までに。 以上です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む