- 投稿日:2020-10-13T21:21:56+09:00
link_toメソッドのpathの引数、要る・要らない
はじめに
アプリケーションを作るときに、いつもlink_toメソッドでエラーが出ていた。しかも、そのリンク先に飛ぶときではなく、link_toメソッドがあるページを表示させたときに、
ActionController::UrlGenerationError
このエラーが出ていて、悩まされた。いつも○○_path
と、ルーティングを確認して記述するところまでは問題がなく、躓かない。ここに( )で引数を渡すとなると、何を渡したらいいのか分からなくなっていた。引数がなくてもOKなパターン
アプリケーションを利用する誰もが同じページに飛ぶ場合は引数がなくてもよい。ログインページやroot_pathのページがこれにあたる。
やっぱりrails routesは便利だった
ターミナルでカレントディレクトリが作成中のアプリケーションのディレクトリで
% rails routesを入力すると、ルーティングを教えてくれる。
pathの記述はもちろん、Prefixの部分を見る。しかし、
ここで着目すべきは、URI Patternの部分。ここで/:idなど、idがURIに含まれている場合は、引数を渡す必要がある。
:idとidがURIに含まれている場合は、引数に(user.id)などとすればよい。
また、引数によっては、.idを省略できる場合もある。
- 投稿日:2020-10-13T20:37:47+09:00
【rails】requireメソッドとpermitメソッド
requireメソッドとpermitメソッドについて学習したため、アウトプットいたします。
この記事を読むと、require,permitメソッドの意味と使い方を理解できます。
requireメソッドとは?
ストロングパラメーターのメソッドの1つで、paramsからとってくるデータのオブジェクト名を指定する。
※ストロングパラメーターについてわからない場合は、Googleで検索してみてください。使い方例def user_params params.require(:user) endこれによってユーザーというオブジェクトのデータを指定しています。
permitメソッドとは?
ストロングパラメーターの1つで、paramsから取ってくるデータのキーを指定する。
使い方例def tweet_params params_permit(:name, :text, :image) endつまり2つの違いはキーを指定するかオブジェクトを指定するか。
そのため、permitメソッドと、requireメソッドを同時に使うこともある。
例def user_params params.require(:user).permit(:name, :email, :password) enduserオブジェクトを指定し、さらにuserオブジェクトのなかに定義されたname,email,passwordのキーを指定している。
- 投稿日:2020-10-13T20:32:43+09:00
ActiveRecordでカラム名のメソッドをオーバーライドしたときに、カラムを参照する方法
背景
モデルにDBのカラム名と同名のインスタンスメソッドを定義し、さらにそのメソッド内でカラムを参照したい
方法
2つ方法がある模様
class Person < ApplicationRecord def name self[:name] end def name read_attribute(:name) end endThe Rails Style Guide では、
self[:name]
のほうをお勧めしている参考
https://github.com/satour/rails-style-guide/blob/master/README-jaJA.md#read-attribute
https://stackoverrun.com/ja/q/5968719
- 投稿日:2020-10-13T18:23:00+09:00
[Rails]deviseの導入
はじめに
deviseとは、ユーザー管理機能を簡単に実装するためのgemです。
目次
1.deviseのインストール
2.deviseの設定ファイルを作成
3.モデルの作成
4.テーブルの作成
5.ビューの編集
6.コントローラーの編集1. deviseのインストール
gemfileに以下を記述します。
gemfilegem 'devise'アプリのディレクトリで以下を実行します。
ターミナル
bundle installgemをインストールした後はサーバーを再起動します。
サーバーを再起動することでgemが反映されます。ターミナル
rails s2. deviseの設定ファイルを作成
deviseを使用するためには、gemのインストールに加え、 devise専用のコマンドで設定ファイルを作成する必要があります。
以下を実行することで、追加したdeviseというgemの「設定関連に使用するファイル」を自動で生成することができます。ターミナル
rails g devise:install3. モデルの作成
deviseを利用する際には、アカウントを作成するためのUserモデルを新しく作成する必要があります。
作成には通常のモデルの作成方法ではなく、deviseのモデル作成用コマンドでUserモデルを作成します。ターミナル
rails g devise userまた、rails g deviseコマンドによりモデルやマイグレーションを自動生成するだけでなく、routes.rbにルーティングも自動的に追加されます。
4. テーブルの作成
必要なカラムを追加する場合は、マイグレーションファイルに記述し以下を実行します。
ターミナル
rails db:migrate5. ビューの編集
カラムを追加した場合は、追加したカラムを入力できるように、新規登録画面のビューを編集する必要があります。
デフォルトでは、deviseのビューファイルは隠れているので、以下を実行します。ターミナル
rails g devise:views6. コントローラーの編集
また、コントローラーを編集したい場合は以下を実行することでdevise管理下のコントローラーを作成することができます。
ターミナル
rails g devise:controllers users
- 投稿日:2020-10-13T18:06:00+09:00
既存のRailaアプリケーションにのせるフロントのフレームワークを比較した話
背景
既存のRailsのアプリケーションにフロントのフレームワークを導入する運びとなりまして、有名どころ3つをチェックポイントに沿って比較しましたのでその話を残しておきます。
今回はこういうやり方で比較したよ、という話なので、もしフレームワークを選ぶことになった際は参考程度に読んでいただき、その時々の状況やプロジェクトに応じて比較方法は変更すればよいと思います。なのでこれが正解というわけではないです。調査結果に誤りがある場合もあると思いますので、調査は自分で公式のものを見てちゃんと行った方がよいです。比較したフレームワーク
今回比較、検討したフレームワークは以下の3つです。
- VueJs
- React
- Angular
ちなみにAngularは、今回導入しようとしているアプリはそんなに大規模というわけではなかったので、ある程度のところでAngularの調査は切り上げ、VueとReactに絞りました。
チェックポイント
今回「まあこれが分かれば比較できそうかもしれない」と考えてチェックポイントをチーム内で相談し決めました。
- フレームワークの概要(特徴)
- 主なプログラミング言語
- 最新バージョン
- 学習難易度
- パッケージサイズ
- GUI
- 既存機能の実装難易度
- Heroku上の動作時における不具合等
- コード管理のしやすさ
- 開発手法
- ドキュメント
- 他フレームワークへの以降性
- ローカル環境構築のしやすさ
比較方法
期間:2週間
調査人数:エンジニア3~4名チームメンバーで上記のチェックポイントを分担し、確認を行っていきました。その際の情報共有はGoogleドキュメントを使用し、適宜必要に応じてHangoutを行いました。
比較結果
チェックポイント VueJs React Angular フレームワークの概要(特徴) OSSフレームワークでコミュニティにより開発・メンテ。GUIのコンポネントのみ提供。必要であれば他のライブラリをインストールする Facebook社により開発・メンテされている。GUIのコンポネントのみ提供する。必要であれば他のライブラリをインストールする Google社により開発・メンテ。フロントエンド用のMVCフレームワーク 主なプログラミング言語 EMACS6 EMACS6 Typescript 最新バージョン(調査当時) 2.6 16.13 10 学習難易度 容易:GUIのコンポネントとライフサイクルを理解すれば問題ない。CSSコードはコンポネントの中に記述してもいい 容易:GUIのコンポネントとライフサイクルを理解すれば問題ない。 難:GUIの作成方法以外、フレームワークのコンポネントを理解する必要がある パッケージサイズ(約) 80KB 100KB 500KB 既存のサイドパーティ Vue Material Kit, Vuetify, Vue Material, Quasar, Bootstrap-Vue Raect Material Kit, Material UI, React Bootstrap, Ant Design, Semantic UI React mdbootstrap, material, ng-bootstrap 既存機能の実装難易度 APIを新たに作成する必要がある。 Vue同様 ー Heroku上の動作時における不具合等 deployして検証 deployして検証 ー コード管理のしやすさ コンポネントで分かれているためコード管理はしやすい Vue同様 ー 開発手法 オブジェクト指向 コンポネント指向 コンポネント指向 ドキュメント 日本語あり 日本語バージョンは英語の直訳 日本語あり 他フレームワークへの以降性 独自フォーマットであるため、開発が進むと後戻りは困難 Vue同様 フルスタックなため代替は困難 ローカル環境構築のしやすさ 導入時の設定は少し困難だが、そこが完了していれば容易 Vue同様 ー 比較結果
既存機能を実際に開発してみて検証をし、ドキュメントを読んで比較した結果今回はVue&Vuetifyになりました。チームメンバーにVueの経験がある人が多かったのも一つです。
- 投稿日:2020-10-13T18:06:00+09:00
既存のRailsアプリケーションにのせるフロントのフレームワークを比較した話
背景
既存のRailsのアプリケーションにフロントのフレームワークを導入する運びとなりまして、有名どころ3つをチェックポイントに沿って比較しましたのでその話を残しておきます。
今回はこういうやり方で比較したよ、という話なので、もしフレームワークを選ぶことになった際は参考程度に読んでいただき、その時々の状況やプロジェクトに応じて比較方法は変更すればよいと思います。なのでこれが正解というわけではないです。調査結果に誤りがある場合もあると思いますので、調査は自分で公式のものを見てちゃんと行った方がよいです。比較したフレームワーク
今回比較、検討したフレームワークは以下の3つです。
- Vue.Js
- React
- Angular
ちなみにAngularは、今回導入しようとしているアプリはそんなに大規模というわけではなかったので、ある程度のところでAngularの調査は切り上げ、VueとReactに絞りました。
チェックポイント
今回「まあこれが分かれば比較できそうかもしれない」と考えてチェックポイントをチーム内で相談し決めました。
- フレームワークの概要(特徴)
- 主なプログラミング言語
- 最新バージョン
- 学習難易度
- パッケージサイズ
- GUI
- 既存機能の実装難易度
- Heroku上の動作時における不具合等
- コード管理のしやすさ
- 開発手法
- ドキュメント
- 他フレームワークへの以降性
- ローカル環境構築のしやすさ
比較方法
期間:2週間
調査人数:エンジニア3~4名チームメンバーで上記のチェックポイントを分担し、確認を行っていきました。その際の情報共有はGoogleドキュメントを使用し、適宜必要に応じてHangoutを行いました。
比較結果
チェックポイント Vue React Angular フレームワークの概要(特徴) OSSフレームワークでコミュニティにより開発・メンテ。GUIのコンポネントのみ提供。必要であれば他のライブラリをインストールする Facebook社により開発・メンテされている。GUIのコンポネントのみ提供する。必要であれば他のライブラリをインストールする Google社により開発・メンテ。フロントエンド用のMVCフレームワーク 主なプログラミング言語 EMACS6 EMACS6 Typescript 最新バージョン(調査当時) 2.6 16.13 10 学習難易度 容易:GUIのコンポネントとライフサイクルを理解すれば問題ない。CSSコードはコンポネントの中に記述してもいい 容易:GUIのコンポネントとライフサイクルを理解すれば問題ない。 難:GUIの作成方法以外、フレームワークのコンポネントを理解する必要がある パッケージサイズ(約) 80KB 100KB 500KB 既存のサイドパーティ Vue Material Kit, Vuetify, Vue Material, Quasar, Bootstrap-Vue Raect Material Kit, Material UI, React Bootstrap, Ant Design, Semantic UI React mdbootstrap, material, ng-bootstrap 既存機能の実装難易度 APIを新たに作成する必要がある。 Vue同様 ー Heroku上の動作時における不具合等 deployして検証 deployして検証 ー コード管理のしやすさ コンポネントで分かれているためコード管理はしやすい Vue同様 ー 開発手法 オブジェクト指向 コンポネント指向 コンポネント指向 ドキュメント 日本語あり 日本語バージョンは英語の直訳 日本語あり 他フレームワークへの以降性 独自フォーマットであるため、開発が進むと後戻りは困難 Vue同様 フルスタックなため代替は困難 ローカル環境構築のしやすさ 導入時の設定は少し困難だが、そこが完了していれば容易 Vue同様 ー 比較結果
既存機能を実際に開発してみて検証をし、ドキュメントを読んで比較した結果今回はVue&Vuetifyになりました。チームメンバーにVueの経験がある人が多かったのも一つです。
- 投稿日:2020-10-13T17:21:32+09:00
Rails で LTI 認証を実装する
LTI 認証とは
LTI認証という規格があります。
LTIとはLearning Tools Interoperability という単語の頭文字で、要するに学習支援ツール間で認証情報をやり取りする際の規格という意味です。認証技術の中でも分野が特定されているかなりニッチな技術なので、知らない方も多いんではないでしょうか。僕も教育工学を専門にする前はLTIという単語すら知りませんでした。
以下にIMS GLOBAL から公式に出されているLTI認証の説明図をのっけて置きます。
個人的には、結局OAuthの一種と理解しているのですが、我々が開発するアプリケーションを Learning Tools, 認証の基盤となる大本のツールを Learning Platform として、Learning Tools は Learning Platform の拡張機能を提供する代わりに、認証情報を Learning Platform からもらいます。これによってユーザーは様々なアプリをユーザーを切り替えることなしに、使い分けることができるという利点があるわけです。このとき、Learning Toolsのほうを LTI Tool Provider, Learning Platformのほうを LTI Consumer と呼んだりもします。
ただ、問題はこれをどう実装するかです。実際、ニッチな技術ゆえにドキュメンテーションに乏しく、ネット上を探しても実装例はあまり公開されていません。そこで今回、この記事では Ruby on Rails を使った LTI 認証の実際について紹介したいと思います。
実装例
ライブラリのインストール
まずは、必要なライブラリをインストールします。
$ bundle add devise $ bundle add ims-lti $ bundle add oauthRails を使うメリットは lti 認証のためのライブラリがあるところです。今回は
ims-lti
を使って実装します。認証キーの登録
config
配下にlti_settings.yml
ファイルを作成します。
内容は以下の内容を記載してください(コンシューマーキー、LTIシークレットは適宜安全な文字列を使用してください)。config/lti_settings.ymlproduction: __consumer_key__: '__lti_secret__' development: __consumer_key__: '__lti_secret__'作成したら、これを読み込むための設定を
config/application.rb
に追加します。config/application.rbconfig.lti_settings = Rails.application.config_for(:lti_settings)コントローラーの作成
ltis_controller
を作って以下の内容を記載しましょうrequire 'oauth/request_proxy/action_controller_request' class LtisController < ApplicationController skip_before_action :verify_authenticity_token, only: :launch def lti_launch # 受け取った consumer key が config/lti_settings.yml の中にあるかどうかを確認 if not Rails.configuration.lti_settings[params[:oauth_consumer_key]] render :launch_error, status: 401 return end shared_secret = Rails.configuration.lti_settings[params[:oauth_consumer_key]] authenticator = IMS::LTI::Services::MessageAuthenticator.new(request.url, request.request_parameters, shared_secret) #Check if the signature is valid if not authenticator.valid_signature? render :launch_error, status: 401 return end #check if the message is too old if DateTime.strptime(request.request_parameters['oauth_timestamp'],'%s') < 5.minutes.ago render :launch_error, status: 401 return end # LTI 情報をsessionに保存 session_data = { "fullname" => authenticator&.message&.lis_person_name_full, "email" => authenticator&.message&.lis_person_contact_email_primary, "user_id" => authenticator&.message&.user_id, "context_id" => authenticator&.message&.context_id, "context_title" => authenticator&.message&.context_title, "tool_consumer_instance_name" => authenticator&.message&.tool_consumer_instance_name } print(session_data) session['lti-authenticator'] = session_data sign_in_and_redirect(User.first) end end
MessageAuthenticator
にわたってきたリクエストと事前にこちらで保持しているキーの情報を渡すことで簡単に認証ができます。認証が成功したら、devise
ライブラリを使ってsign_inすることで、アプリ側での認証を実装しています。最後に
lti_launch
を起動するためのエンドポイントを定義しておきましょう。config/routes.rbmatch 'lti/launch' => 'ltis#lti_launch', via: [:get, :post], as: :lti_launchLearning Platform 側での設定
ここまでできたら、あとは Learning Platform 側で事前に
lti_settings.yml
に記載した認証情報を書いて指定したエンドポイントに遷移するように設定すれば完成です。このやり方は個々のLearning Platformによって異なるので割愛します。(補足)LTI 遷移時に Rails で cross origin error が出たら
config/application.rb
に以下の内容を追記してくださいconfig/application.rbconfig.lti_settings = Rails.application.config_for(:lti_settings) config.action_dispatch.default_headers['Referrer-Policy'] = 'unsafe-url' config.action_controller.forgery_protection_origin_check = false config.action_controller.allow_forgery_protection = false参考文献
- 投稿日:2020-10-13T16:11:19+09:00
デプロイ後に背景画像が適用されない場合の対処法
この記事を書いた背景
デプロイしたら背景画像が表示されない!
調べたら結構そういう人いたため。実施環境
macOS Catalina 10.15.7
VS Code 1.50.0
Ruby 2.6.5
Rails 6.0.0
サーバー:AWS EC2
WEBサーバー:Nginx
アプリケーションサーバー:unicorn 5.4.1対処法
僕はこれでいけました。
デプロイ後、本番に上がったアプリ等で背景画像が表示されます。①背景画像は『/app/assets/images』フォルダに格納する
②背景画像を指定するCSSの種類を『SCSS』にする
③背景画像を指定するCSSの記述『background-image: image-url("画像名");』
scss/*例*/ body { background-image: image-url("wallpaper.jpg"); }※この記述だと逆にローカル環境で背景画像が表示されない...笑
- 投稿日:2020-10-13T15:58:31+09:00
アプリをもっと良くしよう
コメント機能の追加
Commentのscaffoldをする
Commentの著者名、コメント本文、Ideaテーブルへの関係(
reference
)をscaffoldします。
rails generate scaffold comment user_name:string body:text idea:reference
マイグレーションをします。
rails db:migrate
モデルに関係(relation)を追加する
Ideaとcommentオブジェクト間の接続をRailsに認識させます。
app/models/idea.rbclass Idea < ApplicationRecord has_many :commentsapp/models/comment.rbclass Comment < ApplicationRecord belongs_to :ideaコメントフォームの表示と編集
app/views/ideas/show.html.erb<p> <strong>Picture:</strong> <%= image_tag(@idea.picture_url, width: 600) if @idea.picture.present? %> </p> <h3>Comments</h3> <% @comments.each do |comment| %> <div> <strong><%= comment.user_name %></strong> <br /> <p><%= comment.body %></p> <p><%= link_to 'Delete', comment_path(comment), method: :delete, data: { confirm: '削除してもよろしいですか?' } %></p> </div> <% end %> <%= render 'comments/form', comment: @comment %>app/controllers/ideas_controller.rbdef show @comments = @idea.comments.all @comment = @idea.comments.build endapp/views/comments/_form.html.erb<div class="field"> <%= form.label :body %> <%= form.text_area :body %> </div> <%= form.hidden_field :idea_id %>最後に次の行を削除します。
app/views/comments/_form.html.erb<div class="field"> <%= form.label :idea_id %> <%= form.number_field :idea_id %> </div>HTML&CSSを使ってデザインしましょう
アプリケーションのレイアウトを適用する
app/assets/stylesheets/application.cssbody { padding-top: 100px; }上の行を以下のように書き換えます。
app/assets/stylesheets/application.cssbody { padding-top: 60px; }最後に
app/assets/stylesheets/scaffolds.scss
を削除します。ナビゲーションを良くしよう
"New Idea"ボタンをナビゲーションに常に表示します。
app/views/layouts/application.html.erb<li class="active"><a href="/ideas">Ideas</a></li> <li><%= link_to 'New Idea', new_idea_path %></li>アイデアリストのデザイン
以下のように書き換えます。
app/views/ideas/index.html.erb<h1>Listing ideas</h1> <% @ideas.in_groups_of(3) do |group| %> <div class="row"> <% group.compact.each do |idea| %> <div class="col-md-4"> <%= image_tag idea.picture_url, width: '100%' if idea.picture.present? %> <h4><%= link_to idea.name, idea %></h4> <%= idea.description %> </div> <% end %> </div> <% end %> <h2>Ideaの詳細ページをデザイン</h2> 以下のように書き換えます。 ```app/views/ideas/show.html.erb <p id="notice"><%= notice %></p> <div class="row"> <div class="col-md-9"> <%= image_tag(@idea.picture_url, width: '100%') if @idea.picture.present? %> </div> <div class="col-md-3"> <p><b>Name: </b><%= @idea.name %></p> <p><b>Description: </b><%= @idea.description %></p> <p> <%= link_to 'Edit', edit_idea_path(@idea) %> | <%= link_to 'Destroy', @idea, data: { confirm: 'Are you sure?' }, method: :delete %> | <%= link_to 'Back', ideas_path %> </p> </div> </div>
```Carrierrwaveを使ったサムネイルの表示
ImageMagickのインストール
brew install imagemagick
を実行します、gem 'carrierwave'の下に、
gem 'mini_magick'を追加します。その後、以下のコマンドを実行します。
bundle
画像をアップロードしたときにサムネイルを作成する
app/uploaders/picture_uploader.rb# include CarrierWave::MiniMagick version :thumb do process :resize_to_fill => [50, 50] end上の
#
を削除します。サムネイルの作成
app/views/ideas/index.html.erb<%= image_tag idea.picture_url, width: '100%' if idea.picture.present? %>を以下のように変更します。
app/views/ideas/index.html.erb<%= image_tag idea.picture_url(:thumb) if idea.picture.present? %>Deciceで認証機能を追加
devise gemを追加
gem 'devise'を追加します。次に以下のコマンドをターミナルで実行します。
bundle
アプリにdeviseをセットアップ
以下のコマンドを実行します。
rails generate devise:installDeviceの環境設定
environmentファイルにデフォルトのurlオプションを追加します。
config/environments/development.rbconfig.action_mailer.default_url_options = { host: 'localhost:3000' }
end
の前に追加します。app/views/layouts/application.html.erb<% if notice %> <p class="alert alert-success"><%= notice %></p> <% end %> <% if alert %> <p class="alert alert-danger"><%= alert %></p> <% end %> <%= yield %>さらに上の行を追加します。
また、以下を削除します。
app/views/ideas/show.html.erb<p id="notice"><%= notice %></p>同じように
app/views/comments/show.html.erb
でも削除します。
なぜなら、app/views/layouts/application.html.erb
に同じ行を追加したためです。Userモデルのセットアップ
User modelを作るためにbundled generator script を使います。
rails generate devise User rails db:migrateサインアップとログインリンクの追加
ユーザーがログインできる適切なリンク、または案内をナビゲーションバー右上のコーナーに追加する。
app/views/layouts/application.html.erb<p class="navbar-text pull-right"> <% if user_signed_in? %> Logged in as <strong><%= current_user.email %></strong>. <%= link_to 'Edit profile', edit_user_registration_path, class: 'navbar-link' %> | <%= link_to "Logout", destroy_user_session_path, method: :delete, class: 'navbar-link' %> <% else %> <%= link_to "Sign up", new_user_registration_path, class: 'navbar-link' %> | <%= link_to "Login", new_user_session_path, class: 'navbar-link' %> <% end %> </p> <ul class="nav navbar-nav"> <li class="active"><a href="/ideas">Ideas</a></li> </ul>最後にログインしていない時に登録した内容を確認できないようにする。
app/controllers/application_controller.rbbefore_action :authenticate_user!
end
の前に追加します。Gravatarでプロフィール写真を追加
Gravtastic gemを追加
gem 'gravtastic'これを
devise
の下に追加します。Terminalで、次のコマンドを実行します。
bundleGravatarをセットアップ
最後の行の下に次を追加します。
app/models/user.rbinclude Gravtastic gravtasticGravatarを設定する。
app/views/layouts/application.html.erb<% if user_signed_in? %>のなかに,以下のようになるように書き換えます。
app/views/layouts/application.html.erb<% else %> <%= image_tag current_user.gravatar_url %>さらにデザインしよう
headerのデザイン
app/assets/stylesheets/application.cssnav.navbar { min-height: 38px; background-color: #f55e55; background-image: none; } .navbar a.brand { font-size: 18px; } .navbar a.brand:hover { color: #fff; background-color: transparent; text-decoration: none; }tableのデザイン
以下のように書き換えます。
app/views/ideas/index.html.erb<table class="table">以下のコードを使って、画像のサイズを調整します。
<%= image_tag(idea.picture_url, width: 600) if idea.picture.present? %>
app/assets/stylesheets/ideas.scss
の最後に以下を追加します。app/assets/stylesheets/ideas.scss.container a:hover { color: #f55e55; text-decoration: none; background-color: rgba(255, 255, 255, 0); }footerにスタイルを追加
app/assets/stylesheets/application.cssfooter { background-color: #ebebeb; padding: 30px 0; }buttonにスタイルを追加
app/assets/stylesheets/ideas.scs.container input[type="submit"] { height: 30px; font-size: 13px; background-color: #f55e55; border: none; color: #fff; }
- 投稿日:2020-10-13T15:05:40+09:00
Railsでコントローラーの単体テストコード時に「302」のエラーが出た時の対処法
はじめに
前回の記事の続きってわけでも無いのですが、似たような内容にはなっています。
それと「302」のエラーの中のあくまでも1例ですのでよろしく御願い致します。エラー内容
それではまずはコントローラーの単体テストコード実装時に下記のようなエラーが出ました。
ご覧くださいターミナル% bundle exec rspec spec/requests/orders_spec.rb OrdersController GET /index indexアクションにリクエストすると正常にレスポンスが返ってくる (FAILED - 1) indexアクションにリクエストするとレスポンスに出品済みの商品の説明文が存在する (FAILED - 2) Failures: 1) OrdersController GET /index indexアクションにリクエストすると正常にレスポンスが返ってくる Failure/Error: expect(response.status).to eq 200 expected: 200 got: 302 (compared using ==) # ./spec/requests/orders_spec.rb:24:in `block (3 levels) in <top (required)>' 2) OrdersController GET /index indexアクションにリクエストするとレスポンスに出品済みの商品の説明文が存在する Failure/Error: expect(response.body).to include @item.details expected "<html><body>You are being <a href=\"http://www.example.com/users/sign_in\">redirected</a>.</body></html>" to include "商品の説明" # ./spec/requests/orders_spec.rb:29:in `block (3 levels) in <top (required)>' 〜中略〜エラー内容の検証
それではエラー内容を検証していきたいと思います。
今回のエラーの原因となる該当箇所は2つあります。
まず1つ目は下記の部分です。ターミナル1) Failure/Error: expect(response.status).to eq 200 expected: 200 got: 302次に2つ目は下記の部分です。
ターミナル2) Failure/Error: expect(response.body).to include @item.details expected "<html><body>You are being <a href=\"http://www.example.com/users/sign_in\">redirected</a>.</body></html>" to include "商品の説明"エラー内容の検証
それではエラー内容の検証をしていきます。
- まず1つ目のエラーはexpectedで「200」(成功)を期待していますが実際に返ってきたレスポンスは「302」(Found)となっています。 ここで「302」(Found)についての詳しい説明を載せておきます。
302 (Found) エラーとは
「The HyperText Transfer Protocol (HTTP) の 302 Found リダイレクトステータスレスポンスコードは、リクエストされたリソースが一時的に Location で示された URL へ移動したことを示します。ブラウザーはこのページにリダイレクトしますが、検索エンジンはリソースへのリンクを更新しません 。」
上記を簡単に説明しますと「本来遷移したいページではなく違うページにリダイレクトされましたよ」という内容です。
(引用させて頂いた参考サイト)
HTTP レスポンスステータスコードについての参考サイト
- それでは次に2つ目のエラーですが自分が着目したポイントは下記の部分です。
<a href=\"http://www.example.com/users/sign_in\">redirected</a>.まず「users/sign_in」とあるのでログイン画面が関わっていると推測出来ます。そしてその次に「redirected」とあるのでここでもリダイレクトされたということが推測出来ます。
以上の検証内容から推測すると「リダイレクトでログイン画面に飛ばされたのかな?」と仮定することが出来ます。
ではそのような処理をしている箇所はと言うと「authenticate_user!」という部分が該当すると分かりました。ここで少し「authenticate_user!」について説明します。
authenticate_user!とは
処理が実行された時にユーザーがログインしていなければ、そのユーザーをログイン画面に遷移させます。という処理をしてくれるdevise用のメソッドです。
以上の点から自分はテストコード実行時は該当の「authenticate_user!」の箇所をコメントアウトすることにしました。
orders_controller.rbclass OrdersController < ApplicationController before_action :authenticate_user! (この行をコメントアウトする)
再度単体テストコードを実行
ターミナル% bundle exec rspec spec/requests/orders_spec.rb OrdersController GET /index indexアクションにリクエストすると正常にレスポンスが返ってくる indexアクションにリクエストするとレスポンスに出品済みの商品の説明文が存在する indexアクションにリクエストするとレスポンスに出品済みの商品の画像が存在する indexアクションにリクエストするとレスポンスに出品済みの商品の販売価格が存在する indexアクションにリクエストするとレスポンスに購入内容の確認の文言が存在する Finished in 5.79 seconds (files took 10.02 seconds to load) 5 examples, 0 failures上記の通り無事にテストコードを実行することが出来ました。
おわりに
今回のエラー(302)はコントローラーのテストコード実行時に「authenticate_user!」でログイン画面にリダイレクトされていたために起きたエラーでした。結合テストコードだとログインする処理は簡単なのですがコントローラーの単体テストコードの際にログイン出来るのか少し調べた限りではよくわかりませんでしたので今回はコメントアウトをすることで対処しました。
当記事内で参考にさせて頂いたサイト
- 投稿日:2020-10-13T10:20:00+09:00
DockerでRailsアプリの開発環境構築【Docker, Rails, Puma, Nginx, MySQL】
こんにちは.
今回もRailsアプリの開発環境をDockerで構築する手順をまとめてみました.
前回はRails用とデータベース用の2つのコンテナを起動しましたが,今回は,WebサーバーとしてNginxのコンテナも起動してみました.事前準備
環境
Ruby: 2.5.8
Rails: 5.2.4.4
MySQL: 5.7.31
Nginx: 1.19.2
Docker: 19.03.12
Docker Compose: 1.26.2手順
1. ディレクトリ,ファイルの作成
全体の構成は以下の通りです.
それではこの構成図の通り,ディレクトリとファイルを作成していきます.全体の構成/test-app ├── Dockerfile ├── Dockerfile.nginx ├── docker-compose.yml ├── nginx.conf ├── Gemfile └── Gemfile.lockまずは, プロジェクトのルートディレクトリを作成します.
terminal$ mkdir test-appそして, ルートディレクトリの直下に
Dockerfile
Dockerfile.nginx
docker-compose.yml
nginx.conf
Gemfile
Gemfile.lock
これらを作成します.
terminal$ cd test-app $ touch Dockerfile Dockerfile.nginx docker-compose.yml nginx.conf Gemfile Gemfile.lock2. ファイルの編集
上記で作成したそれぞれのファイルの中身は以下のようになります.
(Gemfile.lockは空のままにします.)DockerfileFROM ruby:2.5 RUN apt-get update && apt-get install -y \ build-essential \ node.js WORKDIR /test-app COPY . /test-app RUN bundle installDockerfile.nginxFROM nginx RUN rm -f /etc/nginx/conf.d/* COPY nginx.conf /etc/nginx/conf.d/test-app.conf CMD /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.confcontainers/nginx/nginx.conf# プロキシ先の指定 # Nginxが受け取ったリクエストをバックエンドのpumaに送信 upstream test-app { # ソケット通信したいのでpuma.sockを指定 server unix:///test-app/tmp/sockets/puma.sock; } server { listen 80; # ドメインもしくはIPを指定 server_name _; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; # ドキュメントルートの指定 root /test-app/public; client_max_body_size 100m; error_page 404 /404.html; error_page 505 502 503 504 /500.html; try_files $uri/index.html $uri @test-app; keepalive_timeout 5; # リバースプロキシ関連の設定 location @test-app { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_pass http://test-app; } location /favicon { empty_gif; access_log off; log_not_found off; } }Gemfilesource 'https://rubygems.org' gem 'rails', '~>5.2'docker-compose.ymlversion: '3' services: app: build: context: . dockerfile: Dockerfile command: bundle exec puma -C config/puma.rb volumes: - .:/test-app tty: true stdin_open: true depends_on: - db db: image: mysql:5.7 environment: - 'MYSQL_ROOT_PASSWORD=password' volumes: - 'db-data:/var/lib/mysql' web: build: context: . dockerfile: Dockerfile.nginx volumes: - ./public:/test-app/public - ./tmp:/test-app/tmp ports: - 80:80 depends_on: - app volumes: db-data:3. Appのコンテナ内にRailsのセットアップを行う
terminal$ docker-compose run --rm app rails new . --force --database=mysql --skip-bundle4. tmp/socketsフォルダ作成,作成されたファイルを編集
まず,tmpフォルダ内に
sockets
フォルダを作成します.そして,Railsのセットアップにより作成されたファイルのうち以下の3つを編集します.
-config/database.yml
-config/puma.rb
-config/environments/production.rb
config/database.ymldefault: &default adapter: mysql2 encoding: utf8 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root password: password #docker-compose.ymlのMYSQL_ROOT_PASSWORDの値を設定する host: db #docker-compose.ymlのservice名と合わせる development: <<: *default database: test-app_developmentconfig/puma.rbthreads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } threads threads_count, threads_count port ENV.fetch("PORT") { 3000 } environment ENV.fetch("RAILS_ENV") { "development" } pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } plugin :tmp_restart app_root = File.expand_path("../..", __FILE__) bind "unix://#{app_root}/tmp/sockets/puma.sock" stdout_redirect "#{app_root}/log/puma.stdout.log", "#{app_root}/log/puma.stderr.log", trueconfig/environments/production.rb# Do not fallback to assets pipeline if a precompiled asset is missed. config.assets.compile = true #デフォルトではfalseなので,trueにかえるこの
config/environments/production.rb
の変更はしなくても開発環境の構築については問題はないが,あとあと本番環境にデプロイした際にアセットプリコンパイルのエラーが出たので,ここで変更しています.5. コンテナの起動, DBの作成
terminal$ docker-compose up -d --build $ docker-compose exec app rails db:createこれで http://localhost にアクセスすると, Railsのホーム画面が表示されるはずです.
参考
- 投稿日:2020-10-13T09:39:12+09:00
【Rails】Gem gretelを用いたパンくずリスト作成
そもそもパンくずリストとは
パンくずリストとは下記の写真のようにページを階層順に配列し、ユーザーが操作時に現在どの位置にいるかを可視化したリストです。このようなリストを位置型パンくずリストと呼びます。
他にも属性型パンくずリストといいページを階層的に示したものでなく、そのページがどの種類のカテゴリに属しているかを示すリストもあります。属性型パンくずリストの例としてはECサイトが挙げられます。
パンくずリストを導入することによって主に下記の3点のメリットがあります。
・操作性の向上
→ユーザーがサイト内での位置情報を常に確認できる。滞在時間の向上
→パンくずリストにより階層毎の移動が容易になり回遊性が高まる。SEO効果
→パンくずリストによりクローラーの巡回をサポートする。gretelのインストール
【ドキュメント】
https://www.rubydoc.info/gems/gretel【GitHub】
https://github.com/lassebunk/gretelGemfileにて
gem 'gretel'記載後は下記を実行
$ bundle installこれでインストールは完了です。
設定
下記のコマンドでパンくずリストを設定するためのファイルを作成します。
$ rails generate gretel:installするとこのようなファイルが作成されます。
config/breadcrumbs.rbcrumb :root do link "Home", root_path end # crumb :projects do # link "Projects", projects_path # end # crumb :project do |project| # link project.name, project_path(project) # parent :projects # end # crumb :project_issues do |project| # link "Issues", project_issues_path(project) # parent :project, project # end # crumb :issue do |issue| # link issue.title, issue_path(issue) # parent :project_issues, issue.project # end # If you want to split your breadcrumbs configuration over multiple files, you # can create a folder named `config/breadcrumbs` and put your configuration # files there. All *.rb files (e.g. `frontend.rb` or `products.rb`) in that # folder are loaded and reloaded automatically when you change them, just like # this file (`config/breadcrumbs.rb`).今回ブログアプリの管理画面にパンくずリストを実装するので下記のように記載します。
config/breadcrumbs.rb#管理画面 crumb :root do link "Home", admin_dashboard_path end #記事(一覧) crumb :admin_articles do link "記事", admin_articles_path endコードの説明
config/breadcrumbs.rbcrumb :(設定ファイル) do link "(パンくずリストに表示される名前)", (呼び出し元のパス) endビューの設定
ここでbreadcrumbs.rbに記載したcrumb :admin_articles doが繋がります。
admin/articles/index.html.slim- breadcrumb :admin_articles下記を記載した箇所にパンくずリストが表示されます。
layouts/admin.html.slim
== breadcrumbs
親の設定
最後に下記のようにさらに階層を加えた表示方法を記載します。
config/breadcrumb.rbcrumb :root do link "Home", admin_dashboard_path end crumb :admin_articles do link "記事", admin_articles_path end crumb :edit_admin_article do link "記事編集", admin_articles_path parent :admin_articles end先ほど「記事」のパンくず追加に加えて今回は「記事編集」というパンくずを追加しました。
前回と異なる点は記事と記事編集を紐付けるために記事編集の欄にparent :admin_articlesを記載しております。最後にadmin/articles/edit.html.slimでもビューの設定を終えればパンくずの実装が可能になります。
参照したページの一覧
【ドキュメント】
https://www.rubydoc.info/gems/gretel【Flexible Ruby on Rails breadcrumbs plugin.(GitHub)】
https://github.com/lassebunk/gretel【gretelでパンくずリストを作成】
https://doruby.jp/users/kisuzuki/entries/gretel%E3%81%A7%E3%83%91%E3%83%B3%E3%81%8F%E3%81%9A%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E4%BD%9C%E6%88%90
- 投稿日:2020-10-13T03:41:44+09:00
【Rails】 あいまい検索機能の付け方
経緯
現在絶賛作成中のポートフォリオで、フリマアプリのラクマの仕上げに検索機能をの実装したいと思い作成。さほど難しくはなかったけれども、色々記載しておこうと思います。
環境
ruby 2.6.5
Rails 6.0.3.2
haml使用イメージ図
手順
1、ルーティングの設定
2、検索フォームを作成
3、モデルに定義
4、コントローラーに設定
5、ビューの作成の5つの手順になります。
簡単なので、サックと出来ると思います。ルーティングの設定
今回は、7つの基本アクション以外のアクションを定義します。
7つの基本アクションとは、index
new
create
等のアクションの事ですね。
先ずは、コードからroutes.rbresources :items do collection do get 'search' end end説明ですが、
今回は先程言った通り7つの基本アクション以外で定義します。要は新しいアクションを作るみたいなイメージです。
その為のコードが、collection ~ end
の所です。
get の横のsearch
が新しいアクション名です。そして、
collection
ですが、ここはURLの指定先にidの必要の可否で変わります。
idの可とは、showアクションのような個々に登録されている商品の詳細ページなどに見にいく時にふられるものです(まぁ、ふられると言うと言葉のニュアンス的に違うのですが・・・)
なので、idなしで有ればcollection
idありで有ればmember となります。今回は、特定のページにいく必要がないため、
collection
を使用してルーティングを設定してます。
検索フォームを作成
先ずは、コードから
index.html.haml= form_with(url: search_items_path, local: true, method: :get, class: "search-form") do |f| = f.text_field :keyword, placeholder: "検索する", class: "search-input" %label{for: "search-icon", class: "search-label"} %i.fas.fa-search .search-icon = f.submit "検索", class: "search-btn", id: "search-icon"必要そうな所だけ説明します。
先ずは、urlの設定部分ですが、先程設定したsearchのルーティングで設定されるplefixを書きます。plefixをパスとして書く時は文字の最後に_pathをつけるような書き方をします。
調べ方は、ご存知だと思いますが、
ターミナルでrails routes
です。次に、まぁこれは無理に行う必要はないですが、上記の画像のように、ムシメガネ?みたいなアイコンとsubmit(送信ボタン)の紐付けについてです。
つまり、ムシメガネ?みたいなアイコンを押したら送信ボタンが押されるように設定していると言う事です。やり方は、label:for と id で紐付けます。
上記のコードで言うと、
これと%label{for: "search-icon", class: "search-label"}
これで= f.submit "検索", class: "search-btn", id: "search-icon"
です。
search-icon
って言う同じ名前がありますよね。これで紐付けされています。そして、今回は検索フォームに
f.text_field :keyword
と記述したので、このフォームに入力した値はコントローラーでparams[:keyword]
と書くことで取得する事ができます。
モデルに定義
ここも、コードから
item.rbdef self.search(search) return Item.all unless search Item.where('name LIKE(?)', "%#{search}%") end言い忘れましたが、今回はitemって言う名前でモデル等を作ってます。
説明します。
検索したキーワードが含まれている投稿を取得するために、whereメソッドとLIKE句を利用します。
whereメソッドは、モデル名.where('検索対象となるカラムを含む条件式')とする事でテーブル内の「条件に一致したレコードのインスタンス」を配列の形で取得できます。LIKE句は、曖昧(あいまい)な文字列の検索をするときに使用するもので、whereメソッドと一緒に使います。
詳細は、省きますが今回は、searchが含まれるnameカラムのデータを検索するものです。
詳しく知りたい方は、下記のリンク先が分かりやすいと思います。
【SQL】LIKE句の基本的な使い方~複数検索する場合の方法まで解説そもそも、searchって何?っと思われた方の向けに説明します。
要は引数の話です。
引数のsearch(1行目の(search)
)は、検索フォームから送信されたパラメーターが入ります。イメージしやすく言うと、検索フォームに みかん と入力して送信ボタンを押すとこの引数に みかん が入ると言う事ですね。
後は、文法の話です。
この引数にみかんというデータが入れば定義の中のsearchもみかんになるって訳です。つまり、このまま、みかんネタで言えば、itemテーブルのnameカラムにみかんと言う文字が入っているものを検索するって言う事です。
なので、言ってしまえば、1行目の(search)
はどんな単語でも良いって事ですね。次に、
return Item.all unless search
ですが、これは読んで字のごとくですが、
search(さっきので言えばみかん)と言う文字がなかったら他全てを出力すると言う意味です。そして、最後に1行目の
self.search
の説明です。
現時点だと、.search
というメソッドは使うことができません(この後コントローラーで定義するのに使います)
が、モデルで設定することにより、コントローラーで使用することができるようになります。そして、モデルの中でメソッドを定義する際には、メソッド名の頭にself.
を付けると事で、コントローラーで使えるクラスメソッドになります。以上で、モデルに定義は終了です。
コントローラーに設定
はたまた、ここもコードから
item_controller.rbdef search @items = Item.search(params[:keyword]) end
@items = Item.search(params[:keyword])
のコードは、
上記で述べてきた、今迄の説明で事足りるかと思うので省略します。
ビューの作成
検索結果画面のビューの作成ですが、
ここは、search.html.haml
と言うファイルを作成して、
eachメソッドを使って出力すればオッケーかと思います。search.html.haml.contents__box - @items.each do |item| ここより下は今自分が作っているものに照らし合わせて作成お願いします。これで、全ての実装が完了です!
実装出来なかったなどの不備が有ればご連絡ください!ありがとうございました。
- 投稿日:2020-10-13T01:00:58+09:00
【超初心者向け】autofocus: trueの使用法
autofocus属性
「autofocus: true」とはページを読み込んだらすぐにautofocus属性を記述している部分にカーソルが移動して入力状態になる、というものです。
具体例
一覧ページからマイページへ移動し名前を変更しようとする場合。
一覧ページからマイページボタンをクリックしてマイページに行くと自ら名前のフォーム部分を選択しなくてもカーソルが移動した状態でマイページが表示されます。そのためすぐに編集をすることができます!
⚠️autofocus:trueは1つのhtmlファイルに1つまでということを押さえておきましょう。
記述の仕方
ここでは上記画像のコードをそのままご紹介します。
全体の中で「autofocus: ture」がどのように使用されているのかを把握しましょう。
環境:rails 6.0.0、VScode 1.46、macOS Catalina 10.15app/views/users/show.html.erb<div class="account-page"> <div class="account-page-title"> <h1>マイページ</h1> </div> <div class="account-info"> <h2>ユーザー情報</h2> </div> <div class="account-page-form"> <%= form_for(current_user) do |f| %> <div class="form-field"> <div class="form-field-name"> <%= f.label :name %> </div> <div class="form-field-name"> <%= f.text_field :name, autofocus: true %> </div> </div> <div class="form-field"> <div class="form-field-email"> <%= f.label :email %> </div> <div class="form-field-email"> <%= f.email_field :email %> </div> <br> </div> <%= f.submit "更新する" %> <br> <%= link_to "ログアウト", destroy_user_session_path, method: :delete%> <% end %> </div> </div>おわりに
参考サイトURL→Uhyohyoweb
「autofocus: trueの使用法」に関する記事はいかがでしたか?
autofocus自体はとっても簡単ですが知らないと「何それ?」ってなりますよね。
簡単なことすぎてピックアップされないので今回記事にしてみました!
少しでも理解のお役に立てたら幸いです。
また、いたらない点がございましたらご指摘ください。(初投稿かつ初学者なので皆さんのご指摘がとっても学びにつながります!)
皆さん、最後までご覧いただきありがとうございます。それではまた別の記事でお会いしましょう〜〜!
- 投稿日:2020-10-13T00:23:24+09:00
RailsでCSVインポートする時、nkfコマンドを使ったらめっちゃ楽だった
RailsでCSVファイルをインポートするとき、こんな感じに実装してた。
def read_csv begin rows = CSV.read(file, encoding: 'UTF-8') rescue CSV::MalformedCSVError begin # csvファイルがUTF-8でない場合はShift_JISで読む rows = CSV.read(file, encoding: 'Shift_JIS') rescue CSV::MalformedCSVError, Encoding::InvalidByteSequenceError, Encoding::UndefinedConversionError # csvファイルがUTF-8・Shift_JISでもない場合 @error = 'ファイルのエンコードはUTF-8かShift_JISではありません。' end end rows&.shift # ヘッダーを削除する rows end問題点
例外処理が多くて面倒だし、そもそもインポートできる文字コード2つしかないとか…
解決策
どうやら
nkf
とかいうモジュールを使うとなんでも変換できそうだ…
https://docs.ruby-lang.org/ja/latest/class/NKF.html
- nkfをPCにインストール
brew install nkf
nkf -w --overwrite 変換したいファイルのpath
このコマンドを使えばいい感じに変換できそう。
- Railsの中にこのコマンドを組み込んでみる。
def read_csv(file) system("nkf -w --overwrite #{file.path}") rows = CSV.read(file) rows&.shift # 1行目のヘッダーを削除する rows endすっきりとしたコードになりました。
注意点
あらかじめ
brew install nkf
コマンド等でnkfをインストールしておかないと、nkf
コマンドが使えないので気をつけてください。