- 投稿日:2021-01-23T23:59:22+09:00
投稿3日目
投稿3日目
Ruby超入門 220ページまで
ロジカルシンキングが大切という意味が少しわかった!!
- 投稿日:2021-01-23T23:23:01+09:00
findメソッドとfind_byメソッドはどう違うのか
プログラミングスクールの課題アプリ開発の過程で、findメソッドとfind_byメソッドを勘違いしてまる1日エラーに悩まされた経験から、findメソッドとfind_byメソッドについて整理します。
findメソッド
IDを指定してレコードを取得します。
Fruit.find(1) # 複数のIDを指定して、該当するレコードを取得できる Fruit.find(1,4,6) # 配列でも指定できる Fruit.find([1,4,6]) # 同一ファイル内にidの情報を含むインスタンスがあれば、以下のような書き方ができる Fruit.find(@fruit.id)find_byメソッド
条件を指定してヒットした最初の1件を取得します。IDも条件に指定できます。
Fruit.find_by(name: "strawberry")Fruitsテーブルに以下のようにデータが入っているとします。
Fruitsテーブル | id | name | color | | 1 | apple | red | | 2 | strawberry | red | | 3 | orange | orange | | 4 | banana | yellow |この場合、次のように記述して該当するデータを取得できます。
Fruit.find_by(name: "apple") Fruit.find_by(name: "orange") Fruit.find_by(color: "yellow")個人的なミス経験で恐縮ですが、ぼくはfindメソッドとfind_byメソッドを混同して以下のように記述してエラーに悩まされていました。
Fruit.find(id: @fruit.id)findメソッドを使っているのに、カッコ()の中はfind_byメソッドの文法で記述していました。
どう違うのか
Railsドキュメントを読んでみると、findメソッドはRailsのバージョン1.0.0から、find_byメソッドはRailsのバージョン4.0.2から適用されているので、歴史的にはfind_byメソッドの方が後から登場したメソッドのようです。
機能的には次のような違いがあります。
- findメソッドもfind_byメソッドもIDを指定してレコードを取得することができる
- findメソッドはIDを複数指定していれば複数の値を取得できるが、find_byメソッドは1つのレコードしか取得できない
- find_byメソッドはID以外の条件を指定してレコードを取得できる
結論としては、こんな感じでしょうか。
取得したいレコード 使用するメソッド 1つ findメソッド・find_byメソッド 1つ&IDを指定 findメソッド・find_byメソッド 複数&IDを指定 findメソッドのみ 1つ&ID以外を指定 find_byメソッドのみ 複数&ID以外を指定 ??? 最後のパターンで???が出ました。
このパターンは、findメソッドでもfind_byメソッドでも取得できません。
このときはどうすればよいでしょうか?Whereメソッド
取得したいレコードが「複数&ID以外を指定」の場合はWhereメソッドを使用することで実行可能です。
whereメソッドは条件に当てはまる値を全て取得します。
@fruit = Fruit.where(name: "strawberry")ここまでみるとwhereメソッドがなんでもできて最強じゃないかとも思いますが、findとfind_byメソッドにはできて、whereメソッドにはできないことがあります。
# findとfind_byメソッドで取得した値は、特定のカラムを取得できる @fruit = Fruit.find(1) # もしくは、@fruit = Fruit.find_by(name: "strawberry") @fruit.name # 実行結果 => "strawberry" # whereメソッドで取得した値は特定のカラムを取得できない @fruit = Fruit.find(name: "strawberry") @fruit.name # 実行結果 => NoMethodErrorになる細かい理由は参考させていただいたQiita【Rails】find・find_by・whereについてまとめてみたをご参照ください。
参考資料
Railsドキュメント モデルについて
Qiita【Rails】findとfind_byの違い
Qiita【Rails】find・find_by・whereについてまとめてみた
- 投稿日:2021-01-23T23:21:20+09:00
Formオブジェクトを使用したテーブルの編集・更新のやり方
概要
この記事で使用している言語のバージョンは以下のとおりです。
- Ruby 2.6.5
- Rails 6.0.3.4
Formオブジェクトで編集・更新を行うにはどうするか調べたのですが、バージョンが古いものが多かったので自分なりに考えて出来たやり方をここで共有します。
もっと良い書き方出来るところが絶対あると思いますので修正すべき点は指摘して頂けると大変うれしいです。
今回作ったのはサンプルのアプリなので簡単な作りとなっています。ご了承をよろしくお願いいたします。
作成したコード
stations_controller.rbclass StationsController < ApplicationController def index @stations = Station.all end def new @station = StationForm.new end def create @station = StationForm.new(station_params) if @station.valid? @station.save redirect_to root_path else render :new end end def edit @station = StationForm.new(id: params[:id]) end def update @station = StationForm.new(station_params.merge(id: params[:id])) if @station.valid? @station.update redirect_to root_path else render :edit end end private def station_params params.require(:station_form).permit(:name, :address_url) end endstation_form.rbclass StationForm include ActiveModel::Model attr_accessor :name, :address_url with_options presence: true do validates :name validates :address_url end def initialize(attribute = {}) if !(attribute[:id] == nil) @station = Station.find(attribute[:id]) @address = @station.address if !(self.name = attribute[:name]) self.name = @station.name else self.name = attribute[:name] end if !(self.address_url = attribute[:address_url]) self.address_url = @address.address_url else self.address_url = attribute[:address_url] end else super(attribute) end end def persisted? if @station.nil? return false else return @station.persisted? end end def save station = Station.create(name: name) Address.create(address_url: address_url, station_id: station.id) end def update @station.update(name: name) @address.update(address_url: address_url) end endnew.html.erb<%= form_with model:@station, url:stations_path, local: true do |f|%> <%= render 'error_messages', model: @station %> <div class="field"> <%= f.label :name, "駅名" %> <%= f.text_field :name %> </div> <div class="field"> <%= f.label :address_url, "駅住所" %> <%= f.text_field :address_url %> </div> <div class="actions"> <%= f.submit "登録する" %> </div> <% end %>edit.html.erb<%= form_with model:@station, url:station_path, local: true do |f|%> <%= render 'error_messages', model: @station %> <div class="field"> <%= f.label :name, "駅名" %> <%= f.text_field :name %> </div> <div class="field"> <%= f.label :address_url, "駅住所" %> <%= f.text_field :address_url %> </div> <div class="actions"> <%= f.submit "登録する" %> </div> <% end %>コード解説
おそらくFormオブジェクトで一番重要なのは以下です
station_form.rbdef initialize(attribute = {}) if !(attribute[:id] == nil) @station = Station.find(attribute[:id]) @address = @station.address if !(self.name = attribute[:name]) self.name = @station.name else self.name = attribute[:name] end if !(self.address_url = attribute[:address_url]) self.address_url = @address.address_url else self.address_url = attribute[:address_url] end else super(attribute) end end改善の余地だらけだとは思いますが、ここではStationFormインスタンスの初期化を行っています。
引数として設定している attibute = {}はインスタンスが存在するかどうか判断するためにつかいます。Formオブジェクトのインスタンスが生成される時はnew&createアクション時とedit&updateアクション時です。(下記は他の記述を省略しています)
station_controller.rbdef new @station = StationForm.new end def create @station = StationForm.new(station_params) if @station.valid? @station.save redirect_to root_path else render :new end end def edit @station = StationForm.new(id: params[:id]) end def update @station = StationForm.new(station_params.merge(id: params[:id])) if @station.valid? @station.update redirect_to root_path else render :edit end end新規投稿と編集のインスタンス生成時の違いは保存されたデータが既に存在しているかどうかなのでedit&updateを行う時は編集を行う対象データのidを引数として送りinitializeメソッド内で処理をする必要があります。
station_form.rbif !(attribute[:id] == nil) @station = Station.find(attribute[:id]) @address = @station.address if !(self.name = attribute[:name]) self.name = @station.name else self.name = attribute[:name] end if !(self.address_url = attribute[:address_url]) self.address_url = @address.address_url else self.address_url = attribute[:address_url] end else super(attribute) end引数のidが存在しない場合はsuper(attribute)としてインスタンスを生成します。
(このsuperが何かよく分からない方は参考文献をどうぞ!簡単に言うと何もないinitializeメソッドを行っている認識でいいかと思います。)ここでidが渡された場合は保存されたデータを取得する動きになります。
このタイミングで僕がつまいづいたのはただ情報を取得するだけだとeditのフォームに情報が表示されない点です。原因は簡単でStationFormインスタンス自体に情報が入っていないからです。
staion_form.rbif !(self.name = attribute[:name]) self.name = @station.name else self.name = attribute[:name] end if !(self.address_url = attribute[:address_url]) self.address_url = @address.address_url else self.address_url = attribute[:address_url] endここでStationFromインスタンス自体に初期値を設定しています。
selfがインスタンスを表していて、formで表示しておきたい値を渡している形になります。
条件分岐をしているのはupdateアクションの時用です。
updateアクションが行われる時は引数としてパラメーターを渡しています。stations_controller.rbdef update @station = StationForm.new(station_params.merge(id: params[:id])) if @station.valid? @station.update redirect_to root_path else render :edit end end上記のように記述することでid,name,address_urlが渡されるのでattributeの中に3つの値が入ります。
update時は保存する値をStationFormインスタンスに代入する必要があるので代入をします。ここまでの動きをinitializeメソッドで行っています。
この初期値の設定さえうまく行けばFormオブジェクトをつかった編集と更新はうまくいくはずです。まとめ
以上が個人的にFormオブジェクトをつかった編集と更新のポイントかなと思います。
ただ、先程も述べたようにもっときれいな書き方が出来るところがあるのと、人によって書き方も違うと思うので教えて頂けると大変嬉しいです。この記事がすこしでも参考になれば嬉しいです。
最後までご覧頂きありがとうございました!
- 投稿日:2021-01-23T22:46:48+09:00
rails 検索機能の実装
1.ルーティングの指定
ルーティングの中に検索したいテーブルの中にserchを記述します。以下を例とします。collectionを使うことによって生成されるルーティングのURLと実行されるコントローラーを任意でカスタムできます。
config/routes.rbresources :posts do collection do get 'search' end end2.モデルの指定
モデルを指定します。以下のようにwhereメソッドとLIKE句を使い、検索をかけたいカラムを記述します。
post.rbdef self.search(search) if search != "" Post.where('text LIKE(?)', "%#{search}%" ) else Post.all end end3.この他に検索のカラムを追加したいとき
もしいくつかのカラムを検索につかしたいときは、orを使い"%#{search}%"以下のように記述しましょう。
post.rbdef self.search(search) if search != "" Post.where('text LIKE(?) or title LIKE(?)', "%#{search}%", "%#{search}%") else Post.all end end4 コントローラーにserchアクションを記述
コントローラーにsearchアクション記述をします。この記述でバックエンドの記述は終了です。あとはビューに反映させるだけなので、お好みの形でデザインしましょう。
controllers/posts_controller.rbdef search @post = Post.search(params[:keyword]) end5.最後に
検索機能自体は他のアクションと同じように設定できますので、モデルの指定だけ特徴をつかめば簡単に実装できます。是非実装してみましょう。
- 投稿日:2021-01-23T22:10:31+09:00
$ rails db:seedを用いて初期データを格納
この記事/メモについて(はじめに)
Twitterの呟きやそれに対するリプライ・コメントは、「ユーザーが送信した情報」をデータとしてデータベースに保存する、と言った仕組みのものです。
しかし、データベースへ格納するデータは必ずしもユーザーや第三者が投稿・送信してきたものだけとは限りません。例えば、自分が行ったことのあるおすすめの国について紹介するWebサイトを制作しようとした時。
このサイトでは、ユーザーが「ここの国はおすすめだよ!」「この地域の料理、とても美味しかった!」と呟いたものではなく、開発者のみなさんが現地で感じた思いやおすすめのポイントなどを掲載したいですよね。本記事では、そんな方々のために、開発者が裏側からデータを格納する方法についてご紹介しようと思います。
手順 (2Stepで簡単にできます!)
裏側からのデータの格納は、
①seedファイルに保存したい初期データを記述
②「$ rails db:seed」というコマンドを入力するという実に簡単な方法で行うことができます。
①番の記述の仕方を抑えてしまえば、特に難しい内容はありません。以下で詳しく説明していきます。Step1 seedファイルに保存したい初期データを記述
例として、Countries(プロダクトに合わせて変更)テーブルに開発者側からデータを入れる場合を考えます。
Countriesテーブルには、nameカラムと、説明のためのbodyカラム、さらに滞在日数を表すdayカラムとその予算(万円)を示すbudgetカラムが存在しているとします。ここでは、表のような情報を開発者が入れる初期データとして保存していこうと思います。
ID name body day budget 1 韓国 低予算で初海外旅行におすすめ! 3日 5 2 スペイン 自然より建物好きならヨーロッパ! 1週間 15 3 シンガポール チキンライスは外せない! 4日半 10 保存形式は以下の通りです。文字列と整数が混在している場合を考えます。
・name → 文字列(string型)
・body → 長い文字列(text型)
・day → 文字列(string型)
・budget → 整数(integer型)このようなデータをCountriesテーブルに保存したい時、まず
db/seeds.rb
内に以下のように記述します。db/seeds.rbCountry.create!(name: '韓国', body: '低予算で初海外旅行におすすめ!', day: '3日', budget: 5) Country.create!(name: 'スペイン', body: '自然より建物好きならヨーロッパ!', day: '1週間', budget: 15) Country.create!(name: 'シンガポール', body: 'チキンライスは外せない!', day: '4日半', budget: 10)レコード1つにつき1行分必要となるイメージです。(たくさんのレコードを保存させたい場合に合わせて、より効率の良い書き方もあります。他にも様々な書き方があるので、是非調べてみてください!)
?1point豆知識?
整数(integer型)で保存するbudgetについて、値を「""」や「''」で囲っていないことに注意してください。
→seedsファイルに限らず、プログラミングの世界ではダブル/シングルクオーテーションを用いて囲ったものは基本的に文字列として認識されてしまうので、エラーが生じてしまいます。Step2 seedファイルに記述した内容をデータベースに反映させる
ターミナル、またはコマンドプロンプトで以下のコマンドを実行することで、db/seeds.rbに記した内容をデータベースに反映することができます。
$ rails db:seed以上です!簡単でしたね!
Step3 データベース内のデータを確認/削除する
データベースに保存されているデータについて確認/削除したいとき、
$ rails c
というコマンドを実行します。($ rails c
を終わりにする際はexit
と入力してEnterを押してください。)こちらの内容はseeds.rbを用いて初期データを格納する場合以外でも頻出のコマンドとなるので、別記事に軽くまとめるつもりです。(気が向いたら。。)
======
$ rails c
は頻出のコマンドとなるので、データの確認/削除は「$ rails c」!!と自分に三回言い聞かせましょう。データの確認
以下のようにコマンドを入力してください。Countriesテーブルに保存されているデータが出力されるはずです。
$ rails c irb(main):001:0> Country.all # => 保存されているデータの出力(確認)データの削除
以下のようにコマンドを入力すると、今度はCountriesテーブルに保存されているデータを全て削除することができます。
$ rails c irb(main):001:0> Country.delete_all # => 保存されているデータの削除参考
railsのseedの書き方いろいろ
https://qiita.com/takehanKosuke/items/79a66751fe95010ea5ee【Rails】CarrierWave + seedで初期データに画像ファイルを投入する
(CarrierWaveをすでに実装している方のうち、初期データに画像を入れたい方はこちらの記事が大変わかりやすいのでぜひ見てください!)
https://remonote.jp/rails-carrierwave-seed
- 投稿日:2021-01-23T21:55:44+09:00
【Heroku×Ruby2.6.5】error: failed to push some refs to 'https://git.heroku.com/●●.git'→Herokuのバージョンを下げて対応。
エラーが発生した状況
Heroku create
でデプロイ用のアプリを作成。- データベースの設定や、環境変数の設定を行った。
- 最後に
master
の内容を、Heokuへ反映しようとgit push heroku master
のコマンド実行したところ、下記の通りエラーが発生。エラー画面(ターミナル)
バージョン等
- ruby 2.6.5
- Rails 6.0.3.4
- MySQL Ver 14.14 Distrib 5.6.50
エラーが起きた理由
- エラー文の中に書いてあるHerokuのURLを確認したところ、Ruby2.6.5のサポートが終了したとのことだった。
https://devcenter.heroku.com/articles/ruby-support#supported-runtimes
解決策
(注意!)
ここに書いてある解決策は、アプリのRubyをバージョンアップせずにデプロイする方法。
デプロイ時に、環境構築できるなら、Rubyのバージョンアップを行い、サポートしてもらえるバージョンでデプロイ出来ると良い。エラーの本文内にある、
heroku stack:set heroku-18 -a [ここにはcreateで作成したアプリ名を記載]
を実行したところ、
git push heroku master
のコマンドが実行でき、デプロイすることが出来た。
今回学んだこと
- 実は今回、記事と伊藤さんの動画を見ながらバージョンアップを試みた。
伊藤さんの記事から、アップデートする前に
Gemfile
内をアップデートして一つずつ行うのか?とめっちゃ勉強になった。無事にバージョンアップが出来て、アプリの
Gemfile
を修正し、bundle install
。いざ、
rails s
しようとしたところ、を以下のエラーになってしまった?f.〇〇@〇〇noMacBook-Air breadcrumb % rails s rbenv: rails: command not found The `rails' command exists in these Ruby versions: 2.6.5
なぜそうなってしまったのか調べていたところ、Rubyのバージョンアップを行うには
rbenv
の初期化から行う必要があり、Rubyだけでなく今までrbenv
に設定していたmysql
・yarn
・bundler
等の設定し直しであることを学んだ。?コマンドに言われた通りのバージョンにアップデートする以外にも、Heroku側のバージョンを下げる方法があることを知った。
他のデプロイの選択肢(例えばAWS等)において、Ruby2.6.5でも対応しているものもあるため、Heroku以外の選択肢を選ぶこともありと感じた。
今回は取り急ぎHerokuのバージョンを下げる方法での対応をしたが、今度macのバージョンアップとともにRubyとRailsのアップデートも行いたい。
- 投稿日:2021-01-23T20:26:54+09:00
【if !status else end】否定の否定を考えさせるプログラミングはやめよう
Rubyを例にしますがどの言語でも同じことがいえます。
否定の否定を考えさせるってなに?
たとえば、以下の要件があったとき。
変数
status
がfalse
のときにはいろんな処理
を実施し、true
のときにはちょっとした処理
を実施する。要件に書かれている通りにプログラミングしました。(Ruby)
status = false # bad if !status p 'いろんな処理' else p 'ちょっとした処理' end次に、
ちょっとした処理
が実施される条件は何かを調べる必要が出てきたとき。
「!status
の否定だから、status == true
だな。」
と考えますね。
これが否定の否定を考える、です。プチストレスになりますので、こういうプログラミングは避けましょう。
unless
を使った場合も同様です。
unless
を使うときはelse
ブロックを書いてはいけません。status = false # bad unless status p 'いろんな処理' else p 'ちょっとした処理' end以下のようにリファクタリングします。
status = false # good if status p 'ちょっとした処理' else p 'いろんな処理' endまとめ
if~else~end
では、条件式に否定!
を使わず、trueの処理とfalseの処理を入れ替えましょう。unless
ではelse
ブロックを書かないようにしましょう。if~else~end
に置き換えましょう。
- 投稿日:2021-01-23T20:07:04+09:00
【画像付き】RailsでDeviseを利用してLINEログイン機能を実装
はじめに
自作アプリでLINEBotを作成する際にLINEログイン機能を実装しました。
実装するに当たって様々な記事を参考にさせて頂きましたが, 記事によって記述が異なったり, ここはもう少し簡潔に書けるのでは?と思ったり, 記事通りに書いてもエラーが出たり, そもそも記事が古かったりで苦労しました。。
今後また実装する時に自分の記事さえ見れば導入できるように画像付きでまとめていきたいと思います!
基本的にRailsを想定していますが, LINE Developersの登録などはRails以外の言語でも参考になる部分があるかと思いますので, 少しでも参考になれば幸いです?
0.導入方法
導入方法はおおまかに以下の4つです。順を追って説明します。
1.Railsアプリを作成
2.Deviseを導入
3.LINE Developersに登録
4.LINEログイン機能を導入
5.LINEログイン詳細設定
1. Railsアプリを作成
- 以下の前提で進めていきます。(アプリやコントローラー名は任意の名前にして下さい)
- postgresqlに設定していますが, データベースはお好みで。
ターミナルrails new linelogin_sample -d postgresql rails db:create rails g controller homes index
config/routes.rbRails.application.routes.draw do root 'homes#index' endここまで出来たら
rails s
でサーバーを起動して http://localhost:3000 にアクセスし, 動作確認を行ってみて下さい。エラーが表示されていなければOKです!2.Deviseを導入
LINEログイン機能の前に, まずはDeviseでログイン機能を実装していきます。
2-1.Gemfileの編集とインストール
Gemfile# ログイン機能 gem 'devise'Gemfileを編集したらターミナルで
bundle install
を実行2-2.Deviseをインストール
【公式】 plataformatec/devise
ターミナルrails g devise:install rails g devise User rails db:migrate(※ userの箇所は,任意のモデル名でOKです)
問題がなければ
rails s
でサーバーを立ち上げ,http://localhost:3000/users/sign_in にアクセスすると,ログイン画面が表示されます。
(すでにサーバーを起動している場合は再起動して下さい。)3.LINE Developersに登録
LINEログイン機能を実装するには LINE Developersに登録する必要があります。
まだ登録されてない方はこちらのURL ( https://developers.line.biz/ja/ ) からログイン画面に遷移し, LINEの登録時に設定したメールアドレスとパスワードでログインします。登録が完了するとこのような画面が表示されるので, LINEログインを選択し,
今すぐはじめよう
というボタンをクリックしてください。
今すぐはじめよう
をクリックすると新規プロバイダーを作成する画面が出てきますので, 必要な項目を入力し, プロバイダーを作成してください。例えば, アンケートBotというアプリにLINEログイン機能を導入する場合は画像のように入力していきます。
上記はあくまで一例です。
プロバイダー名, チャネルアイコン, チャネル名, アプリタイプなどは任意のものにしてください。
4.LINEログイン機能を導入
LINE Developersで新規プロバイダーを作成したら, いよいよLINEログイン機能を実装していきます!
4-1.Omniauthのインストール
Gemfileに以下を追加し,
bundle install
を実行。Gemfilegem 'omniauth-line'4-2.環境変数を設定
次にChannel IDとChannel Secretの設定を行います。
今度はGemfileに以下のgemを追加し,bundle install
を実行してください。Gemfilegem 'dotenv-rails'gemを追加したら, アプリのルート配下に
.env
ファイルを作成し, 以下の2つを追加してください。.envLINE_KEY='自身のChannel ID' LINE_SECRET='自身のChannel Secret'【注意!】
このファイルを公開してしまうと悪用されてしまう可能性があるので, 必ずGitの管理下から外してください。
.gitignore
に以下を追加.gitignore/.env4-3.DeviseとLINEログインの設定
次にDeviseの設定ファイルにLINEログインの設定を行います。
- 以下を追加
devise.rbconfig.omniauth :line, ENV['LINE_KEY'], ENV['LINE_SECRET']
:omniauthable
とomniauth_providers: %i[line]
を追加 (TwitterやFacebookログインなども導入する場合は%i[line]
の配列に追加してください)user.rbclass User < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable, :omniauthable, omniauth_providers: %i[line] end4-4.コントローラーの設定
- omniauth_callbacks_controllerを作成します。
ターミナルrails g controller omniauth_callbacks【注】OmniAuthのバージョンが原因でエラーが出ることがあります。
▼バージョンエラーが出た場合の対処
Gemfilegem 'omniauth', '~> 1.9.1'Gemfileに上記のコードを追加し, ターミナルで
bundle update
bundle update
でomniauthのバージョンが変わったのを確認したら,bundle install
を実行。
再度rails g
コマンドでコントローラーを作成して下さい。
- 以下を修正
omniauth_callbacks_controller.rbclass OmniauthCallbacksController < Devise::OmniauthCallbacksController def line; ; end end4-5.ルーティングの設定
- 以下のようにルーティングを設定します。
routes.rbdevise_for :users, controllers: { omniauth_callbacks: "omniauth_callbacks" }ルーティングを
rails routes
で確認し、user_line_omniauth_authorize GET|POST /users/auth/line(.:format) omniauth_callbacks#passthru user_line_omniauth_callback GET|POST /users/auth/line/callback(.:format) omniauth_callbacks#lineこのような表示がされていたらルーティングの設定は完了です!
4-6.モデルの変更
DeviseでUserモデルを作成しているのでそのままUserモデルに変更を加えてLINEログインができるようにしたいと思います。
- 以下のコマンドでマイグレーションファイルを作成
ターミナルrails g migration add_column_to_users
- 作成されたマイグレーションファイルに以下を追加
db/migrate/20201022073739_change_column_to_user.rbclass ChangeColumnToUser < ActiveRecord::Migration[6.0] def change # 以下を追加 add_column :users, :provider, :string add_column :users, :uid, :string add_column :users, :name, :string end endマイグレーションファイルを編集したら
rails db:migrate
でマイグレーションを実行してください。4-7.Userモデルの編集
- 以下を追加
user.rbclass User < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable, :omniauthable, omniauth_providers: %i[line] # 以下を追加 def social_profile(provider) social_profiles.select { |sp| sp.provider == provider.to_s }.first end def set_values(omniauth) return if provider.to_s != omniauth["provider"].to_s || uid != omniauth["uid"] credentials = omniauth["credentials"] info = omniauth["info"] access_token = credentials["refresh_token"] access_secret = credentials["secret"] credentials = credentials.to_json name = info["name"] # self.set_values_by_raw_info(omniauth['extra']['raw_info']) end def set_values_by_raw_info(raw_info) self.raw_info = raw_info.to_json self.save! end # 以上を追加 end4-8.コントローラーを編集
- classの
ApplicationController
をDevise::OmniauthCallbacksController
に変更するのを忘れないように!omniauth_callbacks_controller.rb# ApplicationController を Devise::OmniauthCallbacksController に変更 class OmniauthCallbacksController < Devise::OmniauthCallbacksController # 以下を追加 def line; basic_action end private def basic_action @omniauth = request.env["omniauth.auth"] if @omniauth.present? @profile = User.find_or_initialize_by(provider: @omniauth["provider"], uid: @omniauth["uid"]) if @profile.email.blank? email = @omniauth["info"]["email"] ? @omniauth["info"]["email"] : "#{@omniauth["uid"]}-#{@omniauth["provider"]}@example.com" @profile = current_user || User.create!(provider: @omniauth["provider"], uid: @omniauth["uid"], email: email, name: @omniauth["info"]["name"], password: Devise.friendly_token[0, 20]) end @profile.set_values(@omniauth) sign_in(:user, @profile) end flash[:notice] = "ログインしました" redirect_to root_path end def fake_email(uid, provider) "#{auth.uid}-#{auth.provider}@example.com" end # 以上を追加 endこれで設定は完了です!
http://localhost:3000/users/sign_in にアクセスするとSign in with Line
が追加されていると思います。ただし, 今の状態ではクリックしてもログインできません。LINE Developers側の詳細設定をしていきましょう!
5.LINEログイン詳細設定
5-1. コールバックURL
ログイン時のコールバックURLを設定していきます。
LINE Developersの任意のプロバイダーから
LINEログイン設定
を開いてください。
コールバックURLを設定するフォームがありますので, そこに入力していきます。基本は
https://アプリ名/users/auth/line/callback
で大丈夫です!
念のためrails routes
で URI Pattern を確認してみてください。
ここで注意して欲しいのが, LINEログインを使用する際のURLは
https
でないといけないということです!
http://localhost3000/users/auth/line/callback のようには設定できません。なので開発環境で動作確認を行う際は一工夫しなければなりません。
開発環境でも動作確認を行いたい場合は次のngrok
を参考にしてください。
(ngrokはあくまで一例ですので, 他にも色々やり方はあります。必要のない方は読み飛ばして下さい!)5-2.ngrok
ngrok
はlocalhostに外部から接続できるようにするというサービスです。
簡単に導入できますので説明していきます。
- 以下のコマンドで
ngrok
をインストールしてくださいターミナルbrew cask install ngrok
インストールが終了したらバージョン確認をしてみてください。
以下のようにバージョンが表示されればOKです!❯ ngrok -v ngrok version 2.3.35ngrokのインストールが終わったら、外部アクセス用 https のURLを発行しましょう。
以下のコマンドを実行してください。ターミナルngrok http 3000( 3000 はポート番号なので適宜変更してください。)
コマンドを実行するとこのような感じで表示されると思います。
こちらで表示された http://xxxxxxxx.ngrok.io で外部からlocalhostのWebサーバーにアクセスすることが可能になります。
今回は
https
で接続したいので下の方の https://xxxxxxxx.ngrok.io をコールバックURLに指定してください。【注】ngrokで作成したURLには使用制限があり, 発行して8時間が経過すると, 設定したURLではアクセスできなくなってしまいます。その際は再度
ngrok http 3000
を実行し, 発行されたURLでコールバック先を指定し直してください。→ 以前は8時間だったのですが, 2時間に短縮されているかも。。LINEログインの動作確認だけだと2時間で十分かと思いますが, 他に便利なサービスがあれば追記します?
【Rails6の場合】
Rails6から保護機能が強化され, ngrokで発行したホスト名ではアクセスできないので, 許可したいホスト名をRailsアプリ側に登録しなければなりません。
(Rails5を使用されている方はこちらは読み飛ばして頂いて大丈夫です。)それではngrokで作成したホストをRailsのアプリに登録していきます。
config/environments/development.rb
に下記を記載し、ホワイトリストに許可したいhostを追加すればOKです!
許可したいホスト名にはxxxxxxxx.ngrok.io
の部分を追加してください。config/environments/development.rbRails.application.configure do # 以下を追加 config.hosts << "許可したいホスト名" endただ先ほど説明したように, ngrokは期限が切れるたびに違うURLを発行し直さなければなりません。
そうすると許可したいホスト名も毎回書きかえないといけなくなりますので, 以下の方法も紹介しておきます。
config/environments/development.rbRails.application.configure do # 以下を追加 config.hosts.clear endこれにより, すべてのホスト名に対するリクエストを通過させることができます。
(ただしせっかくRails6で追加された保護機能を無効化してしまうため、どちらを選択するかはお任せします。)ここまでの設定が完了したらngrokで発行したURLにアクセスできるようになります!
すでにサーバーを起動している場合は再起動し, 実際にURLにアクセスして確認してみてください。【注】ngrokとlocalhostのサーバーは同時に起動させてください。終了させる時はどちらも
Ctrl + C
で終了できます。5-3.チャネルの公開
最後に, 作成したチャネルを公開していきます!
上の方に表示されている
非公開
ボタンをクリックすると「チャネルを公開しますか?」という表示が出てきますので, 公開をクリックしてください。
ここまで設定したらLINEログインの設定は終了です!!!
ログイン画面のSign in with Line
をクリックするとログイン画面が表示されますので, そちらからログインできるようになります!
(初回ログインの際は, LINE登録時のメールアドレスとパスワードを求められる場合があります)Messaging API を利用してLINEBotなどを作る場合, LINEログイン機能は大変便利だと思いますので, 少しでも導入する際の参考になれば幸いです。
仕様の変更や補足があれば随時更新していきたいと思います!
お疲れさまでした〜!✨
- 投稿日:2021-01-23T19:52:08+09:00
【Mysqlエラー】Mysql2::Error: Specified key was too long; max key length is 767 bytes
はじめに
アプリ開発中に起こったMySQLのエラーについて忘備録も兼ねて記録しておこうと思います。
エラー文
rails g devise user
でuserモデルを作成し、rails db:migrate
を行うと下記のエラー文が表示。Mysql2::Error: Specified key was too long; max key length is 767 bytes直訳すると「指定したキーは長すぎます。キーの最大範囲は767バイトまでです」
意味は「Mysql2に格納できる最大文字データ量(767バイト)に対してオーバーしてしまったためエラーになった」ということのようです。
エラー解決に向けての予備知識
utf8
文字コードの中で世界で最も普及している文字コード。
通常は1~4バイトで文字を表現するが、MySQLでは3バイトの文字までしか扱えない。
1文字当たり3バイト。utf8mb4
データベースMySQLで扱うための文字コード。
4バイトの文字を扱えるため、絵文字を扱いたい場合はこちらを使用する
→絵文字は4バイトなので、3バイトまでしか扱えないutf8では不可能なため。
1文字当たり4バイト。VARCHAR型
・可変長(長さを変えられる)文字列のこと
・varchar(m)という形で指定する。(mはバイト数。0~65535まで。)
例) varchar(255) varchar(191)
・char型と異なり、末尾に空白は付かない。
・末尾に空白が付いた文字列はそのまま格納される。
↑の場合、取得時も空白が付いたままだが、WHERE句での比較時には削除された状態で比較が行われる。エラー考察
前提条件として
MySQLのインデックスは最大767バイト。
Railsのstringにおけるデフォルト値が255文字(MySQLで保存できるデータ量)。
- 3バイトのutf8では
3バイト × 255文字 = 765バイト < 767バイト
- 4バイトのutf8mb4では
4バイト × 255文字 = 1020バイト > 767バイト
つまり、上記のように文字コードutf8mb4では、
4 × 255 = 1020バイトとなって、MySQLのインデックスの最大数である767バイトを上回ってしまいエラーが発生してしまったということです。解決方法
解決方法は大きく2つあるようで、
①767バイトを超えないように最大文字数を削る
②767バイトを超えてもOKにする今回は簡単そうな①でエラー解決していきます。
結論 : 文字制限をかけるファイルを新規作成する現在の入力できる最大文字数、255文字『varchar(255)』を191文字『varchar(191)』に変更できるファイルを新規作成し、767バイトを超えないようにします。
191文字『varchar(191)』の理由はMySQLのインデックスは最大767バイト
utf8mb4は1文字当たり4バイト必要なので767バイト ÷ 4バイト = 191.75文字
実際のコード
mysql.rb
をconfig/initializer
配下に新規作成しvarcharのlimitを191にしましょう。この
mysql.rb
というファイルによってActiveRecord内のNATIVE_DATABASE_TYPES
という設定を上書きすることができます。ソースはこちら
config/initializer/mysql.rbrequire 'active_record/connection_adapters/abstract_mysql_adapter' module ActiveRecord module ConnectionAdapters class AbstractMysqlAdapter NATIVE_DATABASE_TYPES[:string] = { :name => "varchar", :limit => 191 } #注目 end end endmysql.rb作成前
rails consoleにて確認することができます。
[1] pry(main)> ActiveRecord::Base.connection.native_database_types => {:primary_key=>"bigint auto_increment PRIMARY KEY", :string=>{:name=>"varchar", :limit=>255}, #limitが255になっている #...以下略mysql.rb作成後
:string=>{:name=>"varchar", :limit=>191}と最大文字数が191になっているのがわかりますね。
[2] pry(main)> ActiveRecord::Base.connection.native_database_types => {:primary_key=>"bigint auto_increment PRIMARY KEY", :string=>{:name=>"varchar", :limit=>191}, #ここがmysql.rbで設定した内容に変わる #...以下略これで文字のデータ量を767バイト以内に納めることができました。
この後rails db:migrateを入力すると上手く作動しエラーが解消されました
ちなみに
今回のように、最大文字数を255文字から191文字にする方法ではなく、
最初にconfig/database.yml
に記載した文字コードを途中から変更(今回であればutf8mb4からutf8に変更してマイグレーション)する方法を取ると、もっと面倒臭いエラーになるようです。rails db:migrateをすると消えない謎のファイルが現れ、モデルの作り直しになってしまうとか。
database.ymlの記載された情報は、迂闊に手を出せないので慎重に取り扱う必要がありますね。
参考記事
Qiita記事【MySQL】Mysql2::Error: Specified key was too long; max key length is 767 bytes
- 投稿日:2021-01-23T19:13:52+09:00
RubyonJetsをGithubActionsで自動デプロイする
概要
Ruby on Jetsを用いたアプリケーションをmergeやpushと同時に自動デプロイできるようにします。
GithubActionsが提供するランナーにはAWS CLIやrsync、zipなどが元からインストールされているみたいで、簡単にデプロイすることができました。手順としては2ステップでできます!
1. AWS CredentialsをGithub Secretsに登録
2. .github/workflows/にymlファイルを記述する環境
Ruby: 2.5.7
Ruby on Jet: 2.3.18手順
AWSのCredentialsをGithub Secretsに登録
暗号化されたシークレットを参考にAWS_ACCESS_KEY_IDとAWS_SECRET_ACCESS_KEYを設定してください。
結構簡単に設定できます。GithubActionsの設定ymlを記述
今回の例ではmainブランチにmerge(or push)した際にproductionに自動デプロイできるような設定を記述しました。
/.github/workflows/deploy_to_production.ymlname: Deploy to production on: push: branches: [ main ] jobs: deploy: runs-on: ubuntu-latest strategy: matrix: ruby-version: [ '2.5.7' ] steps: - uses: actions/checkout@v2 - name: Set up Ruby uses: ruby/setup-ruby@473e4d8fe5dd94ee328fdfca9f8c9c7afc9dae5e with: ruby-version: ${{ matrix.ruby-version }} bundler-cache: false # runs 'bundle install' and caches installed gems automatically - name: Bundle install run: bundle install --path vendor/gems - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v1 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: ap-northeast-1 - name: Jets deploy env: JETS_ENV: production run: echo y | bundle exec jets deploy以下の箇所は
jets deploy
時にbundle installが走るpathと揃える目的があります。
こうしないとjets deploy
時にgemの容量がオーバーしてうまくいきませんでした。- name: Bundle install run: bundle install --path vendor/gemsまとめ
stagingのデプロイは
/.github/workflows/deploy_to_staging.yml
など作成して、JETS_ENV: staging
にするだけでOKです!
ちなみにこの記述をしたブランチをmainに反映した時点から自動デプロイが始まるので気をつけてください!参考
- 投稿日:2021-01-23T18:11:44+09:00
【Railsチュートリアル】第2章 Toyアプリケーション 演習と回答
演習と回答
2.2.1 ユーザーページを探検する
2.2.1 - 1
CSSを知っている読者へ: 新しいユーザーを作成し、ブラウザのHTMLインスペクター機能を使って「User was successfully created.」の箇所を調べてみてください。ブラウザをリロードすると、その箇所はどうなるでしょうか?
<p id="notice">User was successfully created.</p>リロード前は上のようになっていて
<p id="notice"></p>リロードしたあとは
User was successfully created.
が消えて空白になっていた。2.2.1 - 2
emailを入力せず、名前だけを入力しようとした場合、どうなるでしょうか?
名前だけでも登録ができる。
2.2.1 - 3
「@example.com」のような間違ったメールアドレスを入力して更新しようとした場合、どうなるでしょうか?
更新できる。
2.2.1 - 4
上記の演習で作成したユーザーを削除してみてください。ユーザーを削除したとき、Railsはどんなメッセージを表示するでしょうか?
User Destroy (1.1ms) DELETE FROM "users" WHERE "users"."id" = ? [["id", 3]]などと表示される。
2.2.2 MVCの挙動
2.2.2 - 1
図 2.11を参考にしながら、/users/1/edit というURLにアクセスしたときの振る舞いについて図を書いてみてください。
割愛。
2.2.2 - 2
図示した振る舞いを見ながら、Scaffoldで生成されたコードの中でデータベースからユーザー情報を取得しているコードを探してみてください。Hint: set_userという特殊な場所の中にあります。
private # Use callbacks to share common setup or constraints between actions. def set_user @user = User.find(params[:id]) end2.2.2 - 3
ユーザーの情報を編集するページのファイル名は何でしょうか?
edit.html.erb
2.3.1 マイクロポストを探検する
2.3.1 - 1
CSSを知っている読者へ: 新しいマイクロポストを作成し、ブラウザのHTMLインスペクター機能を使って「Micropost was successfully created.」の箇所を調べてみてください。ブラウザをリロードすると、その箇所はどうなるでしょうか?
<p id="notice">Micropost was successfully created.</p>リロード前は上のようになっていて
<p id="notice"></p>リロードしたあとはMicropost was successfully created.が消えて空白になっていた。
2.3.1 - 2
マイクロポストの作成画面で、ContentもUserも空にして作成しようとするどうなるでしょうか?
作成できる。
2.3.1 - 3
141文字以上の文字列をContentに入力した状態で、マイクロポストを作成しようとするとどうなるでしょうか?(ヒント: WikipediaのRubyの記事にある設計思想の引用文が140文字を超えているので、これをコピペしてみましょう)
作成できる。
2.3.1 - 4
上記の演習で作成したマイクロポストを削除してみましょう。
それぞれ削除しました。
2.3.2 マイクロポストをマイクロにする
2.3.2 - 1
先ほど2.3.1.1の演習でやったように、もう一度Contentに141文字以上を入力してみましょう。どのように振る舞いが変わったでしょうか?
作成できず、エラーメッセージが出るようになった。
2.3.2 - 2
CSSを知っている読者へ: ブラウザのHTMLインスペクター機能を使って、表示されたエラーメッセージを調べてみてください。
<textarea name="micropost[content]" id="micropost_content">Ruby には Perl や Python とは決定的に違う点があり、それこそが Ruby の存在価値なのです。それは「楽しさ」です。私の知る限り、Ruby ほど「楽しさ」について焦点を当てている言語は他にありません。Ruby は純粋に楽しみのために設計され、言語を作る人、使う人、学ぶ人すべてが楽しめることを目的としています。しかし、ただ単に楽しいだけではありません。Ruby は実用性も十分です。実用性がなければ楽しめないではありませんか。 — まつもとゆきひろ、Ruby プログラミング入門 まえがき 監修者よりのページ</textarea>2.3.3 ユーザーはたくさんマイクロポストを持っている
2.3.3 - 1
ユーザーのshowページを編集し、ユーザーの最初のマイクロポストを表示してみましょう。同ファイル内の他のコードから文法を推測してみてください(コラム 1.2で紹介した技術の出番です)。うまく表示できたかどうか、/users/1 にアクセスして確認してみましょう。
first_user.microposts Micropost Load (0.1ms) SELECT "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? LIMIT ? [["user_id", 1], ["LIMIT", 11]] => #<ActiveRecord::Associations::CollectionProxy [#<Micropost id: 7, content: "hi!", user_id: 1, created_at: "2021-01-23 06:05:27", updated_at: "2021-01-23 06:05:27">]> 2.6.3 :006 >2.3.3 - 2
リスト 2.18は、マイクロポストのContentが存在しているかどうかを検証するバリデーションです。マイクロポストが空でないことを検証できているかどうか、実際に試してみましょう(図 2.17のようになっていると成功です)。
できたので割愛。
2.3.3 - 3
リスト 2.19のFILL_INとなっている箇所を書き換えて、Userモデルのnameとemailが存在していることを検証してみてください(図 2.18)。
user.rbclass User < ApplicationRecord has_many :microposts validates :name, presence: true validates :email, presence: true end2.3.4 継承の階層
2.3.4 - 1
Applicationコントローラのファイルを開き、ApplicationControllerがActionController::Baseを継承している部分のコードを探してみてください。
application_controller.rbclass ApplicationController < ActionController::Base #この行 def hello render html: "hello, world" end end2.3.4 - 2
ApplicationRecordがActiveRecord::Baseを継承しているコードはどこにあるでしょうか? 先ほどの演習を参考に、探してみてください。ヒント: コントローラと本質的には同じ仕組みなので、app/modelsディレクトリ内にあるファイルを調べてみると...?)
app/models/application_recordclass ApplicationRecord < ActiveRecord::Base self.abstract_class = true end2.3.5 アプリケーションをデプロイする
2.3.5 - 1
本番環境で2〜3人のユーザーを作成してみましょう。
作成できました。2.3.5 - 2
本番環境で最初のユーザーのマイクロポストを作ってみましょう
作れました。2.3.5 - 3
マイクロポストのContentに141文字以上を入力した状態で、マイクロポストを作成してみましょう。リスト 2.14で加えたバリデーションが本番環境でもうまく動くかどうか、確認してみてください。
うまく動きました。
さいごに
Railsチュートリアル第2章をクリアしました!
エラーに遭遇しましたが、きちんと文章を読む、検索する、めげない、で解決へたどり着けました。これからもっと難しくおもしろくなってくるようで、楽しみです。
- MVCモデルを知った
- RESTアーキテクチャを知った
- データモデルを作成した
- Twitterっぽい何かを作ることができた
- エラーに遭遇しても検索して解決へたどり着けた
- 投稿日:2021-01-23T17:49:17+09:00
railsでbootstrapを使う
bootstrapとは
洗練されたWebデザインとユーザーインターフェイス要素を簡単に導入できるCSSのフレームワーク。
最大の特徴はアプリケーションをレスポンシブデザインにできること。導入
①gemファイルを記入
Gemfilesource 'https://rubygems.org' gem 'bootstrap', '~> 4.5.0' . . .②ターミナルでbundleをインストールする
$ bundle install③scssファイル作成
/app/assets/stylesheets/application.scss のファイルを作成。
/app/assets/stylesheets/application.scss@import "bootstrap-sprockets"; @import "bootstrap"; . . .④コードの記入
bootstrapはclassを特定のコードに書き変えると自動で色や大きさを変えてくれます。
今回はこのボタンにbootstrapを当ててみます。
公式サイトのCompornents → buttons の中のこのコードを使います。
classの部分をコピーしてコードに貼り付ける。
↓
サーバーを再起動すると、、、
指定したボタンに早変わり!!
- 投稿日:2021-01-23T17:10:08+09:00
Ruby on Railsで簡単に新着マークを作る方法
はじめに
独学で学習中の学生がこの記事を書いています。
間違っているところやこんな書き方はしないなど思われるかもしれませんが、優しく指摘してもらえるととても嬉しいです。作りたいもの
ここで作りたいものは新着マークです。
新しい投稿があると、その投稿から7日間の間だけ表示される新着マークを作りたいと思います。(
7日経つを自動で消える)
※日数は変更可能前提条件
投稿機能と投稿一覧は既に実装済みということで進めていきます。
必要になる情報
1 現在の時間
2 新規投稿された時間
3 新規投稿された時間から7日後の時間作成の流れ
1 現在の時間を取得(可変)
2 投稿された時間の取得(不変)
3 投稿された時間から7日後の時間を取得(不変)
4 3が1よりも先である(未来である)場合に新着マークを表示される1 現在の時間を取得
app/controllers/posts_controller.rbdef index @posts = Post.page(params[:page]).per(10) @current_time = Time.current endindexアクションの1行目は、kaminariを使って既に投稿されている10記事の情報を取得しています。
2行目は、現在の時間を取得しています。Railsでは、2種類のタイムゾーンがあり、様々な現在時間の取得方法がありますが、TimeWithZoneクラスを使う方法が一番良いとされているようなので、Time.currentを使っています。(Time.zone.nowでも同じ)
詳しくは、こちらの記事が参考になると思います。2 投稿された時間の取得と3 投稿された時間から7日後の時間を取得
app/views/posts/index.html.erb<% @posts.each do |post| %> 省略〜 <% post.created_at.since(7.day) %> <% end %>@postsから1記事ずつ取り出し、その記事が作成された時間(2番)をcreated_atで取得、そしてそこにsinceメソッドを使い、投稿された時間から7日後の時間(3番)を取得しました。
※sinceメソッドの引数を変更すれば、新着マークの表示期間を変更可能4 新着マークを表示させる
app/views/posts/index.html.erb<% @posts.each do |post| %> 省略〜 <% if @current_time < post.created_at.since(7.day) %> <div class = "new-mark">新着</div> <% end %> <% end %>投稿された時間から7日後の時間が現在の時間よりも先であれば(未来であれば)新着マークを表示するようにしたいので、if文を使い、その中に、表示したい内容を入れます。
これで、完成です。
※デザインの部分は省略しています。まとめ
今回はRuby on Railsで期間限定の新着マークを作ってみました。
おそらく、実際は、cookieを使って実装する方が、新着情報を使って他に機能を作る時など、色々な面で使いやすいと思います。
なので、次回はcookieでの実装にもチャレンジしてみようと思います。参考文献
- 投稿日:2021-01-23T17:00:22+09:00
ruby silverに合格したのでまとめました(2021年1月)
この記事ってなに?
ruby silverに合格しました。勉強法について誰かのためになるかもしれないのでまとめておきます。
前提
- 2020年新卒です
- この時までプログラミング経験ありません
- rubyの開発は4ヶ月ぐらいです
- たのしいRuvy一周やったぐらい
勉強したこと
- Ruby技術者認定試験合格教本
- ざっと一周した後、巻末のテストを3周しました
- 間違えてわからないことは本で調べて覚えていく感じ
- 一回目は5割とかでした。最終的にはほぼ満点でした。
- RubyExamination
- 5回か6回ぐらいテストしました
- 確か最初は7割あるかないかぐらいだったかな
- 最終的には9割ぐらいでした。
勉強法でのポイント
- 対策を立てる
- 他の合格記事をみてみる
- 知らないメソッド覚える
- 似たような問題は出るので、よく間違える問題は覚えるぐらいでいいと思います。
- 破壊的メソッドなのかどうかを確認する
- 同意の違う名前のメソッドを覚える
- 回答の選択肢になっているもので、挙動がわからないものはすぐ確認する
ぐらいを意識しながら勉強していました。
1日大体2時間から3時間ぐらいで休みの日は5時間か6時間ぐらいやっていたと思います。
ruby silverに向けての勉強期間は二週間弱だったと思います試験当日
- 見直しめっちゃ大事(二問ミスしているのに気が付きました)
- 知らない問題多かった(このメソッドこの使い方あってる?みたいな問題も多かった)
- 一方で、やった問題もでた
まとめ
試験に向けて、という明確な目標があってやりやすかったです
誰かの参考になれば幸いです。
- 投稿日:2021-01-23T16:52:52+09:00
[rails]繰り返した処理の回数をclassにインデックスとして付与する方法
初めに
eachメソッドでテーブルから取得してきた値に対してそれぞれ違った処理をしたい!ときってありませんか?
例えば、、、
vegtables = [キャベツ,トマト,なす]がデータベース上のテーブルに保存されていて、これをeachメソッドを使って値を取得し、"トマト"だけ赤色にしたい、boxの形を変更したい時など。
実装中にハマったので共有します。
結 論
each.with_indexメソッドを使う。
詳 細
コントローラーの記述は以下の通り
vegtables_controller.rbclass VegtablesController < ApplicationController def index @vegtables = Vegtable.all endなお、vegtablesテーブルのveg_nameカラムには
veg_name=[キャベツ,レタス,きゅうり,トマト,なす,ホウレンソウ,タマネギ,ジャガイモ]
が入っています。これにそれぞれ異なるclassを与えたいとき
index.html.erb<% i=0 %> <% @vegtables.each.with_index do |v, i| %> <div class="wrapper_<%= ++i %>"> <%= v.veg_name %> </div> <% end %>とすることで実装できました!
因みに、scssに書いたclassのnameは
.wrapper_0{}
.wrapper_1{}
.wrapper_2{}
・・・
などです。
- 投稿日:2021-01-23T16:48:36+09:00
Railsでgem 'devise'を練習した話
1.何をしたの?
Railsを勉強している最中、ログイン機能に便利なdevise gemに出会ったので、練習がてら2段階認証が必要な簡単なログインアプリを作成することにしました。
作成したアプリはこちらです
https://github.com/yosnak13/Login_APPdevise gemの使い方はこちらの方の記事がとても参考になりました!
https://qiita.com/cigalecigales/items/f4274088f208322523742.なぜそうしようと思ったのか。
自作アプリで動くメイラーを実装できないものか悩んでいたためです。
著者はrailsチュートリアルからrailsを学び、ログイン機能とメイラーの実装方法は学習しました。当時(2020年6月ごろ)チュートリアルでは、SendGridと呼ばれるherokuのアドオンを使用してメイラーを実装するようテキストに書かれていました。しかし、実際にアドオンを実行しようと思ってもメイラーが機能せず、アカウント有効化できないかSendGrid社に問い合わせたところ、「お客様が当社のプラットフォームに適していないと判断したため、アカウントを有効化することができません。」と返事がありました。SendGridアドオンは明確な商用目的がないと使用できないようです。
仕方ありません!アカウントを有効化するにあたり5つ質問に答えて欲しいと指示があったのですが、質問内容かなりガチでした(笑)。英語でのやりとりでしたがいい経験になりました。
現在RailsチュートリアルはMailgunというアドオンを使用するようにテキストが変わっていますが、そちらはどうなのかはまだチェックできておりません!3.やったことを羅列
備忘録を兼ねて実行したことを羅列します
1.rails new LOGIN_APPでアプリ立ち上げ
2.devise gemのインストール
3.rails g devise User
でUserモデル作成
4.db/migrate/XXXXXXXXXXXXXX_devise_create_users.rbに'name'カラムを追加(emailカラムはモデル作成時すでに存在している仕様らしく、今回は'name'のみです)してmigrate
5.rails g devise:views users
でdeviseが管理するビューを作成・編集
6.rails g devise:controllers users
でdeviseが管理するコントローラーを作成・編集
7.route設定
8.ログインページ、パスワード再設定ページ、アカウント作成ページを編集
今回CSSなしなのでデザインはもうシンプルにこんな感じです。9.gmailを使ってメイラーを設定
10.アカウント作成後のリダイレクト先の作成、設定(route, controller, view)
11.ログイン後のリダイレクト先を作成、設定(route, conttoller, view)
これで完成です!!ログインしたらログインおめでとうの文字が現れます(笑)大まかに分けるとこの11工程になりました。
4.メイラーについて
今回はアドオンではなく習ったばかりのgmailのサービスを使用しました。
やり方は1で紹介した記事ほぼ同じやり方してます。
ただそのままgithubにプッシュすると個人情報ばればれなので、dotenv-gemを使って定義した環境変数から呼び出す形式にし、環境変数はgitignoreに記載することで回避しています。
開発環境では無事メールが飛んでくれました。以前のチュートリアルの時は飛ばなかったので少し進歩です(笑)
これでrailsチュートリアルの時に抱えていたモヤモヤがすっきりしました!
次回からログイン機構を搭載するなどメールが必要なときはこの方法を使っていこうと思います。5.deviseの他の機能
deviseには10個のモジュールが搭載されていて、
今回は、ユーザーの作成、編集、削除ができる'Registerable',メールで2段階認証が搭載できる'Confirmable'を使いました。
他の機能は作るアプリによって使うかどうかというところですが、機会があれば使ってみたいですね。
- 投稿日:2021-01-23T16:20:58+09:00
Githubを使ってHerokuへデプロイする流れ
メモとして簡易的な流れを記入しておきます。(mac OS)
前提
Herokuへの登録は完了しているものとします。
データベースにはMySQLを使用します。
Ruby on Railsを使用します。
Rubyはバージョン2.6.5簡易的流れ
下準備
①Heroku CLIのインストール
ターミナル% brew tap heroku/brew && brew install heroku確認のためバージョンを確認
ターミナル% heroku --version②Herokuへのログイン
ターミナル% heroku login --interactive登録したメールアドレスとパスワードを入力してログインします。
デプロイ方法
①Heroku上にアプリケーションを作成
ターミナル上でデプロイしたいアプリケーションのタスクへ移動し、下記コマンドを実行します。
※既に登録されているアプリケーション名は使用できないので注意!ターミナル% heroku create アプリケーション名下記のコマンドで設定できているか確認できます。
ターミナル% git config --list | grep heroku※ fatal: not in a git directoryであれば設定できていません。
②ClearDBアドオンの追加
ターミナル% heroku addons:add cleardb③MySQLに対応するGemについて設定を変更する
下記コマンドでClearDBのURLを変数heroku_cleardbに格納します。
ターミナル% heroku_cleardb=`heroku config:get CLEARDB_DATABASE_URL`ターミナル% heroku config:set DATABASE_URL=mysql2${heroku_cleardb:5}④Heroku上で環境変数を設定
ターミナル% heroku config:set RAILS_MASTER_KEY=`cat config/master.key`下記で確認ができます。
ターミナル% heroku config⑤Stackの指定
ターミナル% heroku stack:set heroku-18 -a アプリケーション名⑥Githubのmaster情報をHerokuへプッシュ
ターミナル% git push heroku master⑦Heroku上でのマイグレーション実行
ターミナル% heroku run rails db:migrate公開の確認
ターミナル% heroku apps:info上記コマンドで確認したWeb URL: のURLへアクセスして確認ができる。
- 投稿日:2021-01-23T16:09:08+09:00
Heroku Profcfileを使わずに使いたい時
Procfileを消すとどうなるか?
基本、herokuを動かす時はProcfileに動かしたいファイルを書くでしょう。
しかし状況によってはHerokuのAdd-onsにある機能を使い、そこで動かしたいファイルを指定すればできる場合もあります。
例えば、Add-onsにあるHerokuSchedulerを使いそこで動かしたいファイルを指定すれば、Procfileを使わなくても、定期的に実行できます。
(https://devcenter.heroku.com/articles/scheduler)ご参考までに。
- 投稿日:2021-01-23T15:09:46+09:00
rails generate scaffoldをしたときに打ち間違いをしてしまったらどうするか
はじめに
Railsチュートリアル第2章で/usersが開けなかったので、原因を調べたら、scaffoldを作成したときに打ち間違いをしていたためでした。
エラーの原因
rails generate scaffold Usser name:string email:string
User
と打ちたかったところをUsser
と打ち間違いをしていますね。エラー解決までの道のり
打ち間違えに気づいたときには、すでに
rails db:migrate
を実行していたため、まずは変更を取り消しからはじめました。rails db:rollback上記のコマンドを実行すると、以下の表示がターミナルに表示されます。
== 20210123005915 CreateUssers: reverting ===================================== -- drop_table(:ussers) -> 0.0047s == 20210123005915 CreateUssers: reverted (0.0122s) ============================そして、scaffoldを削除します。
rails destroy scaffold Usserこれで
rails generate scaffold Usser name:string email:string
を実行する前まで戻ったはずなので、もう一度rails generate scaffold
をします。今度はうち間違えないように慎重に。rails generate scaffold User name:string email:string忘れずに
migrate
します。rails db:migrate == 20210123041232 CreateUsers: migrating ====================================== -- create_table(:users) -> 0.0116s == 20210123041232 CreateUsers: migrated (0.0129s) =============================無事に表示されました!
さいごに
打ち間違えって怖いですね。一文字でも違っていればアウトですもんね。
でもまぁ確かに、私の名前は「え"ま"」でも「え"も」でもなく「え"む"」ですもんね。
さて、Usserってなんと読むのでしょう。「ゆーずずずぁー」って感じでしょうか。どうでもええがな。参考にした記事
- 投稿日:2021-01-23T12:45:31+09:00
Rails × Ajaxでクリックする度booleanが反転するボタンを実装する
はじめに
Railsで非同期通信をする際、リロードせずにbooleanを反転させたいケースがあり、やり方がわからず時間を費やしてしまったので自戒の意味を込めて記事に残させていただきます。
やりたいこと
↓画像のようなボタンを作り、非同期でbooleanが反転するようにしたい。
完成版パラメーター
【ボタンクリック1回目】
Parameters: {"user_groups"=>{"subscribed"=>"false"}}【ボタンクリック2回目(非同期なのでリロードはしない)】
Parameters: {"user_groups"=>{"subscribed"=>"true"}}ルーティング・コントローラー・ビュー
前提
以下の画像のようにuserとuser_groupは1対多の関係になっています。今回boolean反転させるのは
user_groups
テーブルのsubscribed
カラムです。
ルーティング
今回はユーザーが複数所属するグループが『グループ単位でメルマガを購読するかどうか』を変更するオプション(そんなのあまりないかもしれませんが、例としてです・・)をユーザー側で変更できる実装をする前提で、
update_options
というアクション名にします。
update_subscribed
等の名前の方が良いかもしれませんが、今後同じような操作をするボタンを他にも作ることを想定して共通化された名前としています。
また今回使用するのはPATCHアクションのみなので、ルーティングもPATCHの部分のみ記載しています。routes.rbresources :user_groups do member { patch 'update_options' => 'user_groups#update_options' } endコントローラー
user_groups_controller.rbclass UserGroupsController < ApplicationController before_action :set_group def index #set_groupで定義した@groupをviewファイルで使用 end def update_options @group.update_attributes(user_group_params) end private def user_params params.require(:user_group).permit(:subscribed) end def set_group @group = current_user.user_group.find_by(id: params[:id]) end endログイン中のユーザーは以下でcurrent_userとして定義しています。
shared.rbdef current_user @current_user ||= User.find(session[:user_id]) if session[:user_id] endビュー
スタイリングは本題とは外れるので大変恐縮ですが今回は触れずに行きます。
index.slim= link_to update_options_user_path(user_group: {subscribed: !@group.subscribed}), remote: true, method: :patch do .btn | 変更以上で大体実装ができましたが、このままだとボタンを複数回押した際にパラメーターが切り替わりません。
実際に押してみると、【ボタンクリック1回目】
Parameters: {"user_groups"=>{"subscribed"=>"false"}}【ボタンクリック2回目】
Parameters: {"user_groups"=>{"subscribed"=>"false"}}このように非同期でbooleanが反転されません。もちろんリロードすれば成功します。
解決法①
原因は、index.slimの
= link_to
部分がボタンを押した際に書き換えられていないので、パラメーターに変化がありませんでした。
ですので、update_options
アクション側でDBの値を得て変更させれば『非同期で複数回クリックしてもboolean値が切り替わる』ことは実現できました。user_groups_controller.rbclass UserGroupsController < ApplicationController def update_options @group.update_attributes(subscribed: !@group.subscribed) end endindex.slim= link_to update_options_user_path, remote: true, method: :patch do .btn | 変更このようにすれば、クリックを押すたびにDBのboolean値が切り替わります。
しかし、ユーザーが同時に複数人ログインしていてこのボタンを一斉に押されると、DBの値がユーザーの意図しない値に書き換わってしまうことも考えられるので、やはり『パラメーターの値によってDBの値が変更される』方が良さそうです。解決法②(私はこちらを採用しました)
こちらの方法ではJavaScriptを使って
= link_to
のvalue(今回はURL部分のみ)部分を、クリックするたびに書き換える実装をします。index.slim= link_to update_options_user_path(user_group: {subscribed: !@group.subscribed}), id: "change-subscribed-link", remote: true, method: :patch do .btn | 変更まずは先程のslimファイルの
= link_to
部分にidを付与します。index.slimid: "change-subscribed-link"としました。
次にupdate_options
アクションが走った時にJavaScriptが走るようにしたいので、update_options.js.erb
ファイルをindex.slim
と同ディレクトリに作成し、以下をファイルに記載します。update_options.js.erb$("#change-subscribed-link").attr("href", "<%= update_options_user_path(subscribed: {has_filed: !@group.subscribed}) %>")このようにすることで、複数回クリックしても非同期でbooleanのパラメーターが反転するようになります。
こちらのコードではjQueryのセレクターで該当する= link_to
を持ってきて、中身のURL部分だけを上書きしています。少し見にくいですが、検証ツールでどういう挙動なのか確認できます。
このaタグのhref
部分をupdate_options.js.erb
ファイルで書き換えたということです。【ボタンクリック1回目】
Parameters: {"user_groups"=>{"subscribed"=>"false"}}【ボタンクリック2回目(非同期なのでリロードはしない)】
Parameters: {"user_groups"=>{"subscribed"=>"true"}}パラメーターも無事反転しました!
また今後別のボタンを作り、booleanのみを切り替える動作をさせたい場合は、update_options
アクションを使用すれば良いので、一からルーティング、コントローラーを追加する必要もなくなりました!さいごに
誤っている箇所がありましたらご指摘いただきたく存じます。
また、他にも何か良いやり方等ありましたらご教示いただければ幸いです!
- 投稿日:2021-01-23T12:16:04+09:00
【Rails】ルーティングヘルパー
はじめに
ポートフォリオの作成をし、メンターさんにフィードバックをいただいた点があったので今後の為に書き留めておきます。
改善目標として
・Railsっぽいコード(レールに乗ったコード)を目指す。つまり、Railsが用意している便利な機能を活用する。・ルーティングは以下のように設定しています。
config/routes.rbresources :blogsBefore
app/views/blogs/edit.html.erb<h1>ブログ編集</h1> <%= form_with model:@blog, url:"/blogs/#{@blog.id}", local: true do |f| %> <h4>タイトル</h4> <%= f.text_field :blog_title %> <h4>画像</h4> <%= f.attachment_field :image %> <h4>本文</h4> <%= f.text_area :blog_text, size: "40x10" %> <%= f.submit "編集を保存", class: "btn btn-primary" %> <% end %>改善すべきは2行目の「url:"/blogs/#{@blog.id}"」
このようにurlをベタがきしていると、urlを変更したくなった時に修正箇所がとても多くなってしまう。
そこで、ルーティングヘルパーという機能でこのコードを改善します。やったこと
Terminal$ rails routes blogs GET /blogs(.:format) blogs#index POST /blogs(.:format) blogs#create new_blog GET /blogs/new(.:format) blogs#new edit_blog GET /blogs/:id/edit(.:format) blogs#edit blog GET /blogs/:id(.:format) blogs#show PATCH /blogs/:id(.:format) blogs#update PUT /blogs/:id(.:format) blogs#update DELETE /blogs/:id(.:format) blogs#destroyパスとヘルパーメソッドの関係はターミナルから「rails routes」と打って確認できます。
左がヘルパーメソッドに渡すコードで右がそれによって返されるパスという認識です。After
app/views/blogs/edit.html.erb<h1>ブログ編集</h1> <%= form_with model:@blog, url: edit_blog_path(@blog.id), local: true do |f| %> <h4>タイトル</h4> <%= f.text_field :blog_title %> <h4>画像</h4> <%= f.attachment_field :image %> <h4>本文</h4> <%= f.text_area :blog_text, size: "40x10" %> <%= f.submit "編集を保存", class: "btn btn-primary" %> <% end %>最後に
Railsが提供している機能を知り、レールに乗ったコードが書けるように精進します
- 投稿日:2021-01-23T11:54:01+09:00
Couldn`t find Item(Model) without an IDの解決
はじめに
個人でアプリを開発していてわかったことを今回記事にしました。
状況によっては異なる場合がございます。開発環境
pc: macOS Catalina
shell: zsh
rails: 6.0.0
ruby: 2.7.2エラー内容
controller処理でfindメソッドがIDがないと警告を出しています。
itemテーブルの情報を取得する記述をしています。仮説
①ルーティングの影響により記述が間違えていることによりパラメーターのIDを取得することができない
②ビューのURLに引数として指定されたIDが引き渡しができていないことでIDがないと言っている。結論
今回のエラーの解決方法にはルーティングのネストの影響が関係していました。
ルーティングをネストすることで、IDが変わってしまうと言うことです。routes.rbRails.application.routes.draw do devise_for :users root to: "items#index" resources :items do resources :orders , only: [:index, :create] end end% rail routes root GET / items#index item_orders GET /items/:item_id/orders(.:format) orders#index POST /items/:item_id/orders(.:format) orders#create items GET /items(.:format) items#index POST /items(.:format) items#create new_item GET /items/new(.:format) items#new edit_item GET /items/:id/edit(.:format) items#edit item GET /items/:id(.:format) items#show PATCH /items/:id(.:format) items#update PUT /items/:id(.:format) items#update DELETE /items/:id(.:format) items#destroy解説
items controllerでURIは/items/:id(.:format)となっています。
そのため、@item = Item.find(params[:id])とすることでIDが取得することができます。
しかし、Prefixのitem_ordersをみてみるとURIには/items/:item_id/orders(.:format)となっており
IDが変化してしまっています。ですので上記のように記述をしてしまうと、エラーを引き起こしてしまうのです。
@item = Item.find(params[:item_id])とすることでルーティングのURIのIDが一致し取得することができます。ここから、ネストすることの意味も把握する必要があるのだなと実感しました。
参考文献
・ Ruby on Rails 著:小餅 良介
・ 達人に学ぶDB設計徹底指南書 著:ミック
- 投稿日:2021-01-23T09:09:26+09:00
form_withを使って、ユーザーが新規作成される仕組みを理解する
webサービスで新規登録やユーザログインのときに使われる、form_withというヘルパーメソッド。
Railsチュートリアルなどで突然登場して、なんとなく使い方が分かってるけど説明はできない「曖昧状態」になっていませんか。
ぼくもまさにそのひとり。
今回は、form_withを使って、ユーザーが新規作成される仕組みを理解する記事を書いていこうと思います!
そもそも「フォーム」とは?
nameとvalueがペアになってサーバに送られる
nameとvalueはinputやselectやradioなどに付与される
action属性に指定されたURLに対して入力値が送られる
この3つをはじめてみたとき???という感じでした。
例を挙げて説明してみます。
railsチュートリアルから以下のコードを引っ張ってきました。
<%= form_with(model: @user, local: true do |f| %> <%= f.label :name %> <%= f.text_field :name %> <%= f.submit "Create" %> <% end %>これがHTMLソースに変換されると
<form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post"> <label for="user_name">Name</label> <input id="user_name" name="user[name]" type="text" /> <input name="commit" type="submit" value="Create" /> </form>※local: trueとは?
local: trueがない場合、Rails5ではAjaxによる送信という意味になる。
HTMLとしてフォームを送信する場合にlocal: trueが必要になります。例えば、フォームの名前に「たろう」と入力されると
<input id="user_name" name="user[name]" type="text" value="たろう" />
このようになります。そしてformタグのaction属性に指定されたURL("/users" )に対して、nameとvalueが送られます。
コントローラ
@user = User.new(params[:user])
params[:user]というのは、送られてきたnameに対応しています。今回であればname="user[name]" value="たろう"が送られてきているので、@userというインスタンスにname:"たろう"が格納されます。
form_withのしていること
<%= form_with(model: @user, local: true do |f| %> <%= f.label :name %> <%= f.text_field :name %>整理すると、
model: @user・・・入力値を格納するインスタンスとaction属性を指定("/users")
local: true・・・HTMLとしてフォームを送信する場合にlocal: true必要
<%= f.label :name %>・・・フォームのラベルを決めている
<%= f.text_field :name %>・・・HTMLに変換されるとname="user[name]" type="text"になる
何が起きているかわからないとなってしまうform_withですが、
HTMLコードに分解して考えると、理解しやすいですね。
ブラウザの開発者ツールからHTMLソースを見る癖をつけていきましょう。
- 投稿日:2021-01-23T00:47:51+09:00
ruby のLoadErrorでつい忘れがちなこと
よく出るこういうエラー
Traceback (most recent call last):
2: from /Users/****/.**/**.rb:5:in `'
1: from /Users//.rbenv/versions/2.6.3/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
/Users/***/.rbenv/versions/2.6.3/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require': cannot load such file -- parseconfig (LoadError)今回はparseconfigというgemファイルをそもそもインストールしていなかったのが原因でした
解決策
gem install parseconfig -v <バージョン名>
- 投稿日:2021-01-23T00:02:15+09:00
[Ruby]文字列と整列の変数展開に関して(+英語)
こんばんは、たにーです。
今回は、Twitterでもつぶやいたことがある
Rubyにおけるメソッド(文字列と整数の変数展開)に関してです。これはややこしいものかなと思うけども、個人的には
英語として分解して理解すればよりすっと理解できるのではと思います。いつもですが、なにか略をみた際に、
なぜその英語表記なのか(略されているのか)と私は気になってしまいます。笑文字列と整数の変数展開
学習した変数展開は、二つあります。
①.to_s
②.to_iそれらの意味(使い方)と英語で分解してみると、下記の通りになります。
メソッド 機能 略 .to_s 整列 → 文字列へ to string (意味:文字) .to_i 文字列 → 整列へ to integer (意味:整数) 参考例
.to_s に関して
string.rbage = gets.to_s puts "私の年齢は、#{age}歳です。"to_iに関して
※こちらに関して例が思いつきませんでした。
もし何かあればコメントいただけると嬉しいです。
今後勉強していく中で、あった際にはまだ記事を書こうかと思います。個人的には、、
英語として分解してみると、だからそういった表記になるのか!と納得できると思いますし、
変な文字列だったものが、理解できるものへと変わっていくと思います。
そうなれば、きっとプログラミング言語も少しは苦じゃなくなると思います。以上、たにーでした。