- 投稿日:2019-10-08T23:28:48+09:00
Webhookで使われる署名検証をRubyで実装する
自分用メモ
digest = OpenSSL::HMAC.digest("sha256", "key", "data") signature = Base64.strict_encode64(digest) // UDH+PZicbRU3oBP6bnOdojRj/a7DtwE32Cjjas4iG9A=
- 投稿日:2019-10-08T22:41:32+09:00
【Rails】viewにおけるページタイトルの扱い方
開始タグ
ページタイトルの存在がすっぽ抜けていたので設定しました。
方法
ページタイトル例:
ログイン画面|テストアプリ
最初に
/app/views/layouts/
内にある何かのテンプレート内の<title></title>
の中に以下を記述。application.html.erb<title> <%= content_for?(:html_title) ? yield(:html_title) : "" %> |テストアプリ </title>最後に
/app/views/
以下のビューファイルに以下を記述。login.html.erb<% content_for(:html_title) { 'ログイン画面' } %>簡単2STEP!
自分は究極にざっくりとこう解釈。
○
content_for
=コンテンツを1箇所にまとめて他のビューでも使用できるようにしてるんじゃない?
○yield(:html_title)
=yield
とあるから、ビューファイルにcontent_for(:html_title)
があればそこから持ってくるんじゃない?閉じタグ
「全然仕組み分かってないなー!」と文字に起こそうとする思い知らされますね。
「知らなければ知ればいい」と自分を励ましておきます。参考サイト
ActionView::Helpers::CaptureHelper(リファレンス)
Rails: ページタイトルはビューテンプレートのcontent_forで表示すること(翻訳)
- 投稿日:2019-10-08T21:58:45+09:00
Date.today.since(7.days) ←7日後
何日後:since
何日前:ago
どちらも`Dateクラスが持っているメソッドである。
[1] pry(main)> Date.today => Tue, 08 Oct 2019 [2] pry(main)> Date.today.since(3.days) => Fri, 11 Oct 2019 00:00:00 JST +09:00 [3] pry(main)> Date.today.ago(3.days) => Sat, 05 Oct 2019 00:00:00 JST +09:00
- 投稿日:2019-10-08T21:51:56+09:00
【Rails】RSpecでモデルのテストをする
概要
モデルのテストの記述方法を解説します
詳しくはRSpecの公式サイトのモデルに関するページを参考にしてください
今回は一例としてPostモデルのテストを解説します。
前提としてPostにはアソシエーションされたCommentモデルが存在します。spec/models/post_spec.rbrequire "rails_helper" RSpec.describe Post, :type => :model do context "with 2 or more comments" do it "orders them in reverse chronologically" do post = Post.create! comment1 = post.comments.create!(:body => "first comment") comment2 = post.comments.create!(:body => "second comment") expect(post.reload.comments).to eq([comment2, comment1]) end end end基本はRubyの書き方と同じです。コントローラーの記述する感覚で書きます。
post = Post.create!
- postを作成、保存します
create
メソッドはnew
+save
です!
をつけると保存できなかった時にその原因を出力してくれます
comment1 = post.comments.create!(:body => "first comment")
post
に紐づいたcomment
を:body => "first comment"
で作成する- comment2も同様です
expect(post.reload.comments).to eq([comment2, comment1])
post.reload.comments
の値が[comment2, comment1]
と一致するかどうかを確かめるpost.reload.comments
のreload
はデータベースの値を再び取得するためのメソッドです以上がモデルのテストの記述方法の一例の解説です。
これを元に自身のアプリケーションにも適応し、テストしてみてください。疑問、気になるところがございましたら、質問、コメントよろしくお願いいたします!!
- 投稿日:2019-10-08T19:01:49+09:00
returnを使った後置 if の戻り値
returnを使った後置 if の戻り値 が解らなかったから試してみた
def fofofo(dd)
return if dd == 1
c = 2
endfofofo(1)
=> nilfofofo(2)
=> 2ーーーーー
def fififi(dd)
return unless dd == 1
c = 2
endfififi(1)
=> 2ififi(2)
=> nilーーーーー
def fafafa(dd)
return true if dd == 1
c = 2
endfafafa (1)
=> truefafafa (2)
=> 2tureになる時しか返さないのね
- 投稿日:2019-10-08T18:27:04+09:00
Railsチュートリアル 第4章<復習>
第4章の復習メモです。
個人的に重要と思ったことを書きます。
調べたことや、知っていたことも含めて書きます。ヘルパー
ビューやコントローラ、モデルから呼び出せるメソッド。
以下の二種類がある。
- 組み込みヘルパー
- 新しく定義できるカスタムヘルパー
1は、Railsで元々用意されている。
2は、自分で定義でき、以下のファイルに記述する。
app/helpers/application_helper.rb※以下のサイトも参考にさせていただきました
https://www.sejuku.net/blog/28563文字列の表現
文字列は、シングルクォート(')またはダブルクォート(")で囲む。
前者は、囲った物をそのまま表現する。
よって、正規表現(\n等)や、式展開(文字列中に変数を埋め込む)は無効となる。
後者は、両方とも有効。引数、カッコの省略
メソッドにデフォルト引数を設定している場合、引数、カッコを省略できる。
# メソッドの定義 def string_message(str = '') # デフォルト引数として''を設定 . . end # 呼び出す側 string_message最後の引数がハッシュの場合、波カッコを省略できる。
# 以下の二つは同じ意味となる stylesheet_link_tag 'application', { media: 'all', 'data-turbolinks-track': 'reload' } stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'範囲 (range) オブジェクト
1..10
、a..z
のように表現する。
to_aメソッドで配列に変換すると、範囲内の値が全て、配列に格納される。ブロック
{}で囲むパターンと、do~endで囲むパターンがある。
すいません、文章にできるほど理解できていないので、
リンクを貼らせていただきます・・・
https://www.sejuku.net/blog/14291inspectメソッド
対象のリテラル(プログラムに記述するデータ値。コードに書いた値。)を返却する。
>> puts (1..5).to_a # 配列を文字列として出力 1 2 3 4 5 >> puts (1..5).to_a.inspect # 配列のリテラルを出力 [1, 2, 3, 4, 5] >> puts :name, :name.inspect name :name >> puts "It worked!", "It worked!".inspect It worked! "It worked!"以下を参考にさせていただきました
https://www.sejuku.net/blog/77039
http://www.designmap.info/2016/12/16/javascript-3/#i-2クラス、継承
- 投稿日:2019-10-08T18:26:52+09:00
Railsチュートリアル 第3章<復習>
第3章の復習メモです。
個人的に重要と思ったことを書きます。
調べたことや、知っていたことも含めて書きます。Webページの作成
Railsで、Webページ作成に最低必要なのは、以下の3つ。
- URLのルーティング
- 1に対応するコントローラ及び、アクションの作成
- 2に対応するビューの作成
以下のコマンドを実行すると、上記3つを自動生成してくれる。
$ rails generate controller <コントローラ名> <アクション名1> <アクション名2> <アクション名xx>
- ルーティングについて
- config/routes.rbファイルにルーティングが追記される。
- コントローラについて
- 慣習的に、コントローラ名はキャメルケース(頭だけ大文字)で記載する。
- 生成されるコントローラは、スネークケース(単語間を_でつないだ形)になる。
- アクション名は全て小文字にする。また、いくつ書いても良い。
- ビューについて
- コントローラのアクション毎、ビューが生成される。
切り戻しについて
コマンドを打ち間違えて、変なファイルを作ってしまった場合、
元の状態に戻すためのコマンドが用意されている。
- コントローラを戻す
$ rails destroy controller <モデル名> <アクション名1> <アクション名2>
- モデルを戻す
$ rails destroy model <モデル名>
- DBへの反映を1つ戻す
$ rails db:rollback
- DBへの反映を全部戻す
$ rails db:migrate VERSION=0テストについて
$ rails testで、テストを実行できる。
テストコードは、あらかじめ生成されている物もある。
また、Guardを使ってテストを自動化できるみたい。
詳しく理解するのはまたの機会に。Gitについて
git push origin <ブランチ名>で、GitHub上のブランチにPUSHされる。
GitHubにブランチが存在しない場合、新規作成される。最低限、3章まではやろうと思っていたので、目標は達成しました。
4章以降についても、できれば続けていきたいと思います。
- 投稿日:2019-10-08T17:19:58+09:00
Bundler の動作で疑問に思っていたことが理解できた
Bundlerの動作に疑問を持ったきっかけ
数か月前の話になりますが、@jnchitoさんの以下のQiita記事を読ませていただいて
--path vendor/bundle
について改めて考える機会がありました。bundle install時に--path vendor/bundleを付ける必要性は本当にあるのか、もう一度よく考えてみよう
https://qiita.com/jnchito/items/99b1dbea1767a5095d85この記事で特に心動かされたのは、(
--path vendor/bundle
を付けても付けなくても)どっちでもいいなら付けない方を好む理由として挙げられていた「systemにインストールするのがBundlerのデフォルトで、pathを指定するのがオプションだから」という一文でした。確かにデフォルト設定で問題が起きないならデフォルトのまま使うに越したことがないなぁと思います。ただ、gemをグローバルにインストールした場合で1個だけ疑問に思った動作がありました。
上記記事にもありますが、「グローバルにインストールされる」というのはすなわち、Bundlerを使ってインストールしたgemが開発マシン内のどこでも使える状態になる(bundle installしたプロジェクト以外の場所でも使える)ことを意味します。
どこでも使えるとは、例えば静的解析ツールRuboCopを
bundle install
でグローバルにインストールすれば、どこのディレクトリにいようがrubocop
コマンドを実行できる!ということですが、自分の環境ではそのような動作にはならなかったのです…。$ echo "source 'https://rubygems.org'\n\ngem 'rubocop'" >>| Gemfile $ bundle install $ bundle exec rubocop -v # bundle execを付けるともちろん大丈夫 0.75.0 $ rubocop -v # bundle execを付けないとコマンドが見つからない… zsh: command not found: rubocopこれについて、何故そうなるのかやっと理解できました。
先に結論
- rbenvを使用している環境の場合、
bundle install
しただけではshims
ディレクトリが更新されない参考
https://github.com/rbenv/rbenv/pull/638#issuecomment-59375024
rbenv rehash
を明示的に行うことで、shims
ディレクトリが更新されて、どこのディレクトリにいようがrubocop
コマンドを実行できる!- rbenvを使用していない環境(aptで直接インストール等)であれば、今回の事象はそもそも起きない
自分の環境
- Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-65-generic x86_64)
- rbenv 1.1.2-4-g577f046
- ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-linux]
- Bundler version 2.0.2
色々試したこと
gem install rubocop
したらどうなのか??そもそもBundlerを経由しなかった場合どうなるのか知りたかったので試してみました。
$ gem install rubocop $ rubocop -v # ちゃんとコマンドが見つかる 0.75.0大丈夫そうです。ということはBundlerが原因…と思いましたが、そういえばrbenvを当たり前のように使っていたので、rbenvを使わなかったらどうなるのか試してみました。
sudo apt install ruby
で入れたRubyだとどうなのか??厳密にはrbenvでインストールするrubyバージョンと合わせるべきですが、今回は横着しました…。
rbenvを使用していないまっさらな環境で以下を実行します。$ sudo apt install -y ruby $ ruby -v ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux-gnu] $ sudo gem install bundler $ echo "source 'https://rubygems.org'\n\ngem 'rubocop'" >>| Gemfile $ bundle install # 本件と関係ないエラーが出る場合があるが、ruby-dev等 足りないライブラリをインストールすると解消する $ bundle exec rubocop -v # bundle execを付けるともちろん大丈夫 0.75.0 $ rubocop -v # bundle execを付けなくても大丈夫! 0.75.0なるほど、ということはrubyのバージョンに因る問題か、rbenvに何かあるのかな?
…詳細は書きませんが、rbenvでruby 2.5.1をインストールして試しても同様だったので、rbenvに何かありそうです。
rbenvの仕組み
rbenvのGitHubリポジトリを読むと、rbenvの
shims
について記述があります。
rbenvはPATH
の先頭にshims
ディレクトリを挿入することで、rubyのバージョンを変更した際のコマンド切替をよしなに制御してくれています。その他参考
rbenvの使い方と仕組みについて
https://qiita.com/Kodak_tmo/items/73147ed4f0eec54d6e94古い記事だと
rbenv install
実行後はshims
を更新する為にrbenv rehash
を実行すること!と書いてあったりするのですが、
5年ほど前のPull requestsでrbenv rehash
を自動で処理するように変更されています。
なので、普段rbenv rehash
を実行することはあんまりないんじゃないかなー…と思います。(違っていたらごめんなさい…)今回の件、なんとなく
shims
が更新されてないんじゃない?と思ったので明示的にrbenv rehash
したらどうだろうと思い試してみました。$ echo "source 'https://rubygems.org'\n\ngem 'rubocop'" >>| Gemfile $ bundle install $ bundle exec rubocop -v # bundle execを付けるともちろん大丈夫 0.75.0 $ rubocop -v # bundle execを付けないとコマンドが見つからない… zsh: command not found: rubocop $ rbenv rehash # shimsディレクトリを更新すると… $ rubocop -v # bundle execを付けなくても大丈夫! 0.75.0思っていた動作になりました!
Pull requestsをよくよく読んだら書いてあった
先ほどの
rbenv rehash
が不要になったPull requestsをよくよく読んだら書いてありました!
bundle install
した際 複数回rbenv rehash
が実行されるのを防ぐ為にそうなっているとのこと。Bundlerの並列性の為にrbenv rehash
を一回だけ処理するのは難しかったとのことです。そもそもBundlerを使用している時点で
bundle exec
を付けてコマンド実行すると思うので実用上何も問題は起きないと思います。ですが、引っかかっていた些細な疑問が解決して良かったです!
- 投稿日:2019-10-08T15:40:07+09:00
Ruby on Rails アプリ作成のはじめのはじめ
Ruby on Rails作成におけるアウトプット用も兼ねて記載していきます。
間違い等あればご連絡ください。新規Railsアプリケーションの作成
アプリケーションを配置するディレクトリを作る。
自分の作成したい場所までターミナルで移動する。
cd
現在のディレクトリ(カレントディレクトリ)を移動する
mkdir
新しくディレクトリを作成する
pwd
現在のディレクトリ(カレントディレクトリ)のパスを表示する
ls
現在のディレクトリ(カレントディレクトリ)のファイル一覧を表示する新規アプリケーションを作成
ターミナルで「rails new」コマンドの実行
rails new アプリケーション名 -オプション名これでRuby on Railsのアプリ制作における雛形ができるので、ここから色々と編集していくことで立派なアプリへと成長させていくことが可能となる。
- 投稿日:2019-10-08T14:19:37+09:00
Procの実行方法いろいろ
Procに引数を渡して処理を実行する方法はいくつかあります。
以下は全て同じ結果を返します。proc = Proc.new do |a| puts "This is proc: #{a}" end # オーソドックスな記法 proc.call(1) # callを省いたシンタックスシュガーな記法 proc.(2) # 添字で引数を指定して呼び出す記法 proc[3] # ===で引数を指定して呼び出す記法 # ===が実装されていることでwhen句に手続きを渡せるようになっている proc === 4出力結果
This is proc: 1 This is proc: 2 This is proc: 3 This is proc: 4
- 投稿日:2019-10-08T13:22:18+09:00
Rubyの定数について
概要
Rubyの定数の仕様が他のプログラミング言語と異なるという話は有名です。
定数はオブジェクトを割り当てる"ラベルのようなもの"です。
オブジェクト(数値リテラル等を含む)=定数そのものではない、ということですね。本記事はコンテナオブジェクトの凍結についてのTipsを主にしています。
本題
例えばC言語で定数を定義し、それを変更してみるとこうなります。
sample.c#include<stdio.h> int main(void) { const int TEISUU = 30; printf("%d\n",TEISUU); TEISUU = 20; printf("%d\n",TEISUU); return 0; }$gcc sample.c > error assignment of read-only variable 'TEISUU'こんな感じでエラー吐きます。
そりゃ当たり前ですよね。定数って定義してますから。さて、そんなTEISUUをRubyでも定義してみましょう。
sample.rbTEISUU = 30 TEISUU = 25 puts "できたよ" if TEISUU == 25$ruby sample.rb >sample.rb:2: warning: already initialized constant TEISUU >sample.rb:1: warning: previous definition of TEISUU was here >できたよふむふむ、エラー出てるなよしよし…
!?>できたよ
なんじゃこりゃあ
Rubyは定数を変更しても警告を出すにとどまり、
実際に変更できてしまいます。自由だあああああああああああああ警告の内容は、
二行目:
TEISUU
定数はすでに初期化してるぜ
一行目:以前のTEISUU
を定義したのはここだぜですね。優しい。
Rubyではファイル実行時に’-w’オプションを指定することで警告が表示されますが、
Ruby1.8.7から定数の再代入の際にオプション無しでもエラーが出るようになりました。
ちょうど序盤の"できたよ"ってところで起きてる警告ですね。
ご指摘感謝します。定数の扱い方
実はそもそも、Rubyではクラスやモジュール名も定数なんですよね。
Rubyは先頭が大文字の語句を定数だと識別します。
TEISUU
も定数だし、Array
も定数です。クラス等は変化できますよね。
あとからメソッドを追加したりもできます。でも、特にゲームのタイトルとかURLとか、固定しておきたいものは変更しなくてもいいですよね。
配列オブジェクトなどのコンテナに要素を追加、要素を削除するといった挙動を再現したい場合には、コンテナオブジェクトを凍結させてみましょう。
sample.rbmodule Defaults NETWORKS = ["192.168.1","192.168.2"].freeze end class Klass include Defaults def foo Defaults::NETWORKS << "192.168.3" end end Klass.new.foo() #=>can't modify frozen array (FrozenError)エラー内容は、
「凍結した配列は修正できないよん」です。このように、 Rubyについてもオブジェクトを凍結させることで他言語の定数と同じような挙動を得られます。
さて、定数という言葉で騙される人が多いのだが、定数というのは「いったん 指すオブジェクトを記憶したら二度と変えない」という意味である。定数の指すオブジェクトそれ自体が変わらないわけではない。英語で言うなら、 constantよりもread onlyのほうがよりよく意図を示しているだろう (図2)。 ちなみにオブジェクト自体が変化しないよう指示するにはfreezeという 別の方法を使う。
凍結の落とし穴
さて、オブジェクトを凍結させる方法を学んだ私達ですが、
実は先程の凍結方法には、1つの落とし穴があります。次のコードを見てみましょう。
sample.rbmodule Defaults NETWORKS = ["192.168.1","192.168.2"].freeze end class Klass include Defaults def foo Defaults::NETWORKS.each do |item| item[3] = "hai" if item.class == String end p Defaults::NETWORKS end end Klass.new.foo() #=> ["192hai168.1","192hai168.2"]
String
オブジェクトにインデックスを与えると、
先頭から[i]
番目の文字を指すのはご存知かと思いますが、今回の場合は空白ですね。
なんと、
配列オブジェクトをフリーズしても要素はフリーズされない
ということです。
私達がフリーズする動機は、
- もちろん配列
NETWORKS
に新たに要素が加えられる事も許さない- 要素それぞれのアドレスが変わる事も許したくない
からですよね。(そんな前置きなかったですけど)
しかし、このように要素は書き換わってしまいました。
これには、次のような解決策があります。
1.map!などのメソッドで要素それぞれをフリーズしてみる。
EffectiveRubyに書いてあるやり方の内の1つです。
sample.rbmodule Defaults NETWORKS = ["192.168.1","192.168.2"].map!(&:freeze).freeze end自分も最初何をやっているのか全くわからなかったですが、
map(&:メソッド名)
で、各要素にメソッドを適用することが出来るみたいです。Rubyではやたら使う記法だそうですし、実際かっこいい。
前半の
map!
メソッドで各要素をフリーズして、その後のメソッドチェーンで
配列自体をフリーズしている、ということです。これで、先程のコードを実行した時にエラーが出ます。
sample.rbmodule Defaults NETWORKS = ["192.168.1","192.168.2"].map!(&:freeze).freeze end class Klass include Defaults def foo Defaults::NETWORKS.each do |item| item[3] = "hai" if item.class == String end p Defaults::NETWORKS end end Klass.new.foo() #=> '[]=' can't modify frozen String FrozenError2.%記法を使う
sample.rbmodule Default NETWORKS = %w(192.168.1 192.168.2).map!(&:freeze).freeze
これはRuby2.1以上で実装されたものですが、(訂正)少なくともRuby1.8.7での実装が確認されました。ご指摘感謝します。
%記法かっこよくないですか?簡潔でみやすい。
どうやらこの記法はメモリ管理に一役買っているようで、
リソースの消費を少し軽減できるとか。すっきりしましたか?
Rubyのエラーメッセージでよく
[]=
だとか+
が出てきますが、
Rubyではこういった演算子や識別子なども立派なメソッドだからです。Arrayクラスの公式リファレンスを見てみるとよくわかります。
インスタンスメソッドの欄に記号がずらずら並んでるわけですね。EffectiveRubyの中でも特にディープな部分だと思う(そして私がスルーした)項目に、
演算子のオーバーライドの話があります。sample.rbdef <=>(other) return nil unless other.is_a?(Version) ... endとかいうやつです。
いつか手を出そうとは思いますが、いかんせんディープな話題過ぎてあまりついていけませんでした…凍結の落とし穴その2
注意・Effective Rubyに載っているコードを基盤に、’frozen?’メソッドを使ってわかりやすくした以下の文章ですが、情報に誤りがある可能性があります。
Effective Rubyに実際に記載されているので、現在進行形でこの本の勉強をしている方の為に残しておきますが、コメント欄をご一読ください。さて、凍結について理解を深めた私達は、
もう怖いものはありません、とばかりに次のコードを書きました。sample.rbNUMBER = 10 NUMBER.freeze p NUMBER.frozen? #=>true
frozen?
メソッドは、そのオブジェクトが凍結しているか判定して真偽値を返します。わかりやすい。凍結すれば不変的なオブジェクトというわけですから、
当然次のようなコードはエラーを起こすはずです。
sample.rbNUMBER = 10 NUMBER.freeze NUMBER = 50 p NUMBER #=> 50WHY JAPANESE PEOPLE!?
はい、最大の混乱ポイントの登場です。
最初の、
sample.rbTEISUU = 30 TEISUU = 25 puts "できたよ" if TEISUU == 25このコードのような形ですね。
Rubyでは、
既存の定数に新しい値を代入しても文法違反にはなりません。EffectiveRubyでも「この方法は不格好で状況によっては面倒すぎるが単純である。」
と述べられています。解決策はこちら。
sample.rbmodule Namespace NUMBER = 10 end Namespace.freeze Namespace::NUMBER = 50 #=> FrozenError簡単ですね。
モジュールやクラスで定数をラッピングして、それごと凍結させる。
場合によっては定数を格納する専用のクラスやモジュールを定義して、
freezeする手間を省く事を検討してもいいのだとか。注意!
こちらの記事で述べたことを思い出してください。
クラスパスセパレータを記述せず
NUMBER
に50を代入すると、
Namespace
内の定数とは別のスコープに新たな定数NUMBER
が定義されます!これは間違えやすいミスなので気をつけて下さいね。
最後に
Rubyの定数とオブジェクトの凍結について解説しました。
EffectiveRuby挑戦中の皆様一緒に頑張りましょうね。
- 投稿日:2019-10-08T11:40:17+09:00
【コピペで済ませたい人向け】 rbenvのインストールを環境構築からパスチェックまとめ [2019版]
コマンドを探しにきた人に
# macOS brew tap homebrew/core && brew install apple-gcc42 # Ubuntu/Debian/Mint sudo apt install autoconf bison build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm5 libgdbm-dev # CentOS/Fedora yum install -y gcc-6 bzip2 openssl-devel libyaml-devel libffi-devel readline-devel zlib-devel gdbm-devel ncurses-devel # openSUSE zypper install -y gcc6 automake gdbm-devel libffi-devel libyaml-devel libopenssl-devel ncurses-devel readline-devel zlib-devel # Arch Linux pacman -S --needed base-devel libffi libyaml openssl zlibecho 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc eval $(rbenv init) source ~/.bashrc rbenv install 2.x.x rbenv local 2.x.x動かない場合(既存の環境など)
パスとバージョンを確認
which rbenv rbenv -v which ruby ruby -v which gem gem -v which bundle bundle -v※インストールしてもパスが適用されていない場合は手動で通す。
# [command]はパスが間違っているコマンド名 cd $(which ruby) unlink [command] ln -s $HOME/.rbenv/bin/[command] [command]解説
コマンドの最新はWiki参照
ここでは執筆時点の最新を公式Wikiより引用。また、bash_profileではなくbashrcに書く理由はリンク先の通り。
筆者環境
WSLを使用している。
実行環境にbashを使用しているのでzshやfishでは実行できないかもしれない。cat /etc/os-release # NAME="Ubuntu" # VERSION="18.04.3 LTS (Bionic Beaver)" # ...動機
rbenvの情報が多いので解説はいいとして、そういうのは既に分かっている側の立場としては検索するのも面倒なんでお手軽にできるものが欲しかった。
執筆時点では、後述の筆者環境のみ検証しており、必要に応じて他環境も追記したい。
- 投稿日:2019-10-08T11:38:06+09:00
Rails6 のちょい足しな新機能を試す91(ActiveRecord annotate編)
はじめに
Rails 6 に追加された新機能を試す第91段。 今回は、
ActiveRecord annotate
編です。
Rails 6 では、 ActiveRecord で、発行される SQL にコメントを含めることができるようにannotate
メソッドが追加されました。
ログに出力して解析したり、デバッグしたりするときに便利そうです。Ruby 2.6.4, Rails 6.0.0 で確認しました。
$ rails --version Rails 6.0.0今回は、User の CRUD を作り、一覧ページを表示するとき、そこで実行される SQL がどのコントローラのどのアクションから呼ばれているのかわかるようにしてみます。
プロジェクトを作る
rails new rails_sandbox cd rails_sandbox
User の CRUD を作る
name をもつ User の CRUD を作ります
bin/rails g scaffold User nameコントローラとアクションの名前を返すメソッドを定義する
full_action_name
というプライベートメソッドをApplicationController
に追加しますapp/controllers/application_controller.rbclass ApplicationController < ActionController::Base private def full_action_name "#{self.class.name}##{action_name}" end endApplicationRecord に scope を追加する
annotate
を使った scope を1つApplicationRecord
に追加します。app/models/application_record.rbclass ApplicationRecord < ActiveRecord::Base self.abstract_class = true scope :called_from, ->(from) { annotate("called from #{from}") } endUserController#index を変更する
User.all
がUsersController#index
から呼ばれていることがわかるように、修正します。app/controllers/users_controller.rbclass UsersController < ApplicationController ... def index @users = User.all.called_from(full_action_name) end ... end実際に一覧ページを表示してコンソールを確認する
rails server
を実行し、ブラウザから http://localhost:3000/users にアクセスし、コンソールを確認します。
SQL 文にコメント"called from UsersController#index" が含まれていることがわかります。... User Load (0.4ms) SELECT "users".* FROM "users" /* called from UsersController#index */ ...試したソース
試したソースは以下にあります。
https://github.com/suketa/rails_sandbox/tree/try091_activerecord_annotate参考情報
- 投稿日:2019-10-08T11:17:36+09:00
Ruby 2.6 から CSV の空行のパース結果が変わった
Ruby で CSV を処理するときに、空行を無視するために
empty?
を使って下記のように書いていました。require "csv" CSV.foreach("foo", headers: :first_row) do |row| next if row.empty? p row end
headers
を指定した場合、行はCSV::Row
で表現されますが、Ruby 2.6 からはCSV::Row#empty?
はfalse
を返すようです。#!/bin/sh RBENV_VERSION=2.5.1 ruby -rcsv <<EOS CSV.parse("\n", headers: %w(a)) do |row| p row.empty? # true end EOS RBENV_VERSION=2.6.4 ruby -rcsv <<EOS CSV.parse("\n", headers: %w(a)) do |row| p row.empty? # false end EOS
p row
などでみてみると、2.5 ではフィールドの情報を持っていないのに対し、2.6 ではフィールドの情報を持っています。#!/bin/sh RBENV_VERSION=2.5.1 ruby -rcsv <<EOS CSV.parse("\n", headers: %w(a)) do |row| p row # #<CSV::Row> p row.to_a # [] p row.to_hash # {} end EOS RBENV_VERSION=2.6.4 ruby -rcsv <<EOS CSV.parse("\n", headers: %w(a)) do |row| p row # #<CSV::Row "a":nil> p row.to_a # [["a", nil]] p row.to_hash # {"a"=>nil} end EOSドキュメント には、
empty?
などは Array に delegate されると記載があります。上記のように 2.6 ではto_a
の返り値が空ではないのでempty?
がfalse
を返すようです。空行の読み飛ばしは
CSV::Row#empty?
を使うのではなく、CSV.new
等のオプションにskip_blanks: true
を指定するのがよさそうです (2.5, 2.6 とも)。
- 投稿日:2019-10-08T09:57:30+09:00
wp2txtを使い捨てで使う
wp2txt
機械学習における自然言語処理等のチュートリアルで「訓練データようにWikipediaを全文ダウンロードしてplain textにして使いましょう」というシーンで出てくるツールです。Rubygems で bin/ にインストールされる、Ruby のプログラム。
この記事は
ぼくもまさに上述の流れで使おうと思ったのですが、ちょっと調べると付随するgemがいろいろインストールされるのでローカル環境でbundler使った方が良いよ、という記事をいくつか見ました。うん、確かにそのとおり。使わないgemをやたらシステムワイドにインストールするのは躊躇しちゃうし、wp2txt自体恐らくWikipediaをplain textに変換したらもう使わないだろうから、最後は
rm -r
あたりで全部まとめて簡単に消したいですもんね。…が、そういう記事のとおりにやってもなぜかぼくの環境では
/usr/local/lib/site_ruby/2.5.0/rubygems.rb:284:in `find_spec_for_exe': can't find gem wp2txt (>= 0.a) with executable wp2txt (Gem::GemNotFoundException)というエラーが出てうまく行きません。自分自身が bundler のしくみを良く理解していないのが原因と言えばそれまでなのですが、簡単な検索では解決法が出てなかったので同じエラーに悩む方がいるかも知れないと思いここに書いておきます。
解決策
wp2txt のスクリプトの先頭の辺りに
require 'bundler/setup'
と書く。それだけです。ようはbundler使ったスクリプトの標準的な書き方にすれば良いということです。最初から順を追って手順解説 (面倒な人はここから読み始めればok)
まずは何はなくとも Ruby と bundler をインストールしてください。Ruby は各 OS の流儀で入れるとして、Bundler は
gem install bundler
で入るはずです。さて本題。今から 『
tutorial
というフォルダを掘って > そこでwp2txtを使って > 終わったら消す』 という流れで解説します。$ mkdir tutorial $ cd tutorial $ bundler init Writing new Gemfile to /PATH_TO/tutorial/Gemfile $ echo 'gem "wp2txt"' >> Gemfile $ bundler install --path . # ここでローカルディレクトリを指定すれば後腐れなく rm できるここまでで必要なファイルが
tutorial/ruby
以下にインストールされます。wp2txt
はtutorial/ruby/2.5.0/bin/
等に入っています (2.5.0の部分は各自の環境依存)。これを前項の『解決策』のとおり改変します。と言っても1行追記するだけです。#!/usr/bin/env ruby2.5 # # This file was generated by RubyGems. # # The application 'wp2txt' is installed as part of a gem, and # this file is here to facilitate running it. # require 'bundler/setup' # <- この1行を追記 require 'rubygems' version = ">= 0.a"あとは実行するだけでokです。
tutorial
にWikipediaをダウンロードしているならこんな感じ。PATHが通っていないのできちんと書く必要があります。$ ./ruby/2.5.0/bin/wp2txt --input-file jawiki-latest-pages-articles.xml.bz2あとかたづけ
もうwp2txt使わないと思ったら、そのフォルダ (この例なら
tutorial
) 内のruby/
,.bundle/
,Gemfile
,Gemfile.lock
を消してしまってokです。$ pwd # まとめて rm するときは念のため自分の居場所を再確認しましょう。 /PATH_TO/tutorial $ rm -rf ruby .bundle Gemfile Gemfile.lock参考
ちなみにwp2txtの場合、どんなgemが一緒にインストールされたか確認してみたらこんなでした。
$ ls ruby/2.5.0/gems/ htmlentities-4.3.4 nokogiri-1.10.4 trollop-2.9.9 mini_portile2-2.4.0 parallel-1.18.0 wp2txt-0.9.1
- 投稿日:2019-10-08T09:38:45+09:00
capybaraとselenium-webdriverとは
capybaraとselenium-webdriverとは
capybara
統合テスト(Feature Spec/フィーチャースペック)を書くときに、ブラウザにを仮想的に操作するためのgem。
細かい動作まで検証できる。selenium-webdriver
capybaraはシンプルなブラウザシミュレータ(つまりドライバ)を使って、 テストに書かれたタスクを実行していきます。このドライバは Rack::Test というドライバで、速くて信頼性が高いのですが、JavaScript の実行はサポートしていません。
javascriptをテストするためにselenium-webdriverというgemをを使います。CapybaraでもデフォルトのJavaScript ドライバになっていて、
デフォルトでは Capybara は selenium-webdriver に対して Firefox を使ってテストを実行するように伝えます。ですのでChromeを使いたい場合はそのように設定しなければなりません。
- 投稿日:2019-10-08T08:25:23+09:00
【個人開発】プログラミングを勉強したので誰かの書き込みを表示するだけのWebサイトを作った
kotoniwa
何をするwebサイトなのか
ユーザーそれぞれが好きな言葉を書き込む、そして画面をクリックすると誰かが書いた言葉がランダムでぼんやりと出てくるだけのサイト。
使ったもの
ruby
rails
javascript
jquery
Nginx
unicorn
postgresql自分のスキル
専門学校でサーバーとネットワークの勉強をしていたけど、プログラミングの経験はほぼ0(シェルスクリプトちょっとやったかなくらい)。
他人が書いたrailsアプリを自分が立てたapacheサーバーで公開した事はある。
railsもjavascriptもコードを見たことはあります程度。
自分で1からコードを書いてというのはこれが初めて。
勉強したこと
udemyでjavascriptとrailsとhtmlとcssの講座を購入してみたけど最初にざっと見ただけであまり活用しなかった。結局これ実際にやってみないとよくわからないな、と思ったので。
実装したいと思ったことをその都度ググって、よくわからなかったらそこを深掘りして、みたいな感じで作りながら学習を進めた。
作るまでの流れ
現在はサーバー運用系のお仕事をしていて、web系の方に転職してみようかなという思いが出てきたのでとりあえず何かを作ってみることに。
今まで自分で一からwebサイトを作ったことはなかったのであんまり難しいことをやろうとすると挫折するだろうと思い、とにかくシンプルなものを作りたかった。
wikipediaをランダムで表示したりするやつとかのランダム系のサイトが好きだったのでそんな感じのをイメージしていて、「なんでも好きに書いていい」となった時に皆がどんなことを書くのかに興味があったのでこれを作ろうと思った。
感想
とりあえず公開まで持っていけてよかった。
こんな簡単な感じのサイトでもここまで躓きポイントが大量にあるのか…と思ったので、作ろうと思っても途中で諦めてしまう人は大量にいると思う。
次はもうちょい真面目なwebサービス感のあるサイトを作る予定。
もっと技術つけてはやく転職したい。
- 投稿日:2019-10-08T06:49:04+09:00
Rails on Railsにおける命名規則
- 投稿日:2019-10-08T05:21:40+09:00
Vagrant + RailsでHerokuにHello ,World!する
vagrantローカル環境でhello world!を表示するアプリを作成しherokuにデプロイするまでの忘備録
環境
Ruby 2.4.0
Ruby on Rails 5.1.7
rbenv 1.1.2-2-g4e92322
Node.js v4.9.1
bundler 2.0.2
Vagrantローカル環境構築
https://qiita.com/karlley/items/0812bd33a3952ea40de5
上記URLを参考に環境構築
上記URLではRails 5.1.6で進めていますが今回は5.1.7を使用
順番に進めれば
/home/vagrant/centos67/your_workspace/your_app
にアプリが作成され「Yay! Your on Rails!」まで表示できるはずですまずはローカル環境でHello World!
作成されたアプリのファイルを編集し「Hello World!」が表示されるようにします
修正する使用するファイルは2つ
app/controllers/application_controller.rb
config/route.rb
上記のファイルを以下のように修正
app/controllers/application_controller.rbclass ApplicationController < ActionController::Base protect_from_forgery with: :exception def hello render html: "Hello, World!" end endconfig/route.rbRails.application.routes.draw do root 'application#hello' end
http://192.168.33.10:3000
で「Hello World!」が表示されているか確認Git
- 初期設定
- Initial commit
1. 初期設定
HerokuのデプロイにはGitを使用するので初期設定
設定を確認
$ git config --list core.repositoryformatversion=0 core.filemode=true core.bare=false core.logallrefupdates=true core.ignorecase=trueusernameとemailが未設定の場合は下記コマンドで設定
$ git config --global user.name "Your Name" $ git config --global user.email your.email@example.com $ git congit --list user.name=Your Name user.email=your.email@example.com core.repositoryformatversion=0 core.filemode=true core.bare=false core.logallrefupdates=true core.ignorecase=true設定を反映し、初期化
$ git init Reinitialized existing Git repository in /home/vagrant/centos67/workspace/hello_app/.git/上記コマンドを実行するとアプリのルートディレクトリに
.git
が作成されます2. Initial commit
Git設定後、最初のコミットを作成
ファイルをリポジトリに追加、確認
$ git add -A $ git status # On branch master # # Initial commit . .リポジトリにコミット、確認
$ git commit -m "initialize repository" 56 files changed, 1181 insertions(+), 0 deletions(-) create mode 100644 .gitignore . .$ git log commit 28b... Author: Your Name <your.email@example.com> . .最初のコミットが作成されました
データベース
- postgreSQL
- sqlite3
- 設定したGemをインストール
1. postgreSQL
Herokuで使用するデータベースはデフォルトでpostgreSQLなのでGemの設定
Railsの開発環境でのデフォルトはsqlite3
Gemfileに下記を追記
Gemfilegroup :production do gem 'pg', '0.20.0' end
:production do
は本番環境のみで使用するという意味2. sqlite3
既存のsqlite3の記述をコメントアウト、または削除
Gemfile#gem 'sqlite3'開発/テスト環境のみの仕様に変更する為、
group :development, :test do
にgem 'sqlite3'
を追加Gemfilegroup :development, :test do # sqlite3 for development/test only ← 追記 gem 'sqlite3' ← 追記 # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] # Adds support for Capybara system testing and selenium driver gem 'capybara', '>= 2.15' gem 'selenium-webdriver' end3. 設定したGemをインストール
$ bundle install --without production
--without producton
をオプションで付ける事で本番環境へのデプロイの失敗を防止pg gemを追加したことやRubyバージョンを指定したことをGemfile.lockに反映させないと、本番環境へのデプロイで失敗してしまうためです。
引用:RailsTutorilal
Gemfileを変更したので再度コミット
$ git commit -a -m "Update Gemfile for Heroku"
-a
オプションは変更のあったすべてのファイルという意味Heroku
- Herokuとは
- Heroku CLI インストール
- ssh鍵を追加
- デプロイ
1. Herokuとは
webアプリ用ホスティングサービス
Gitを使う事で簡単に本番環境にデプロイできる
Heroku本番環境ではデータベースにpostgreSQLを使用(Railsの開発環境でのデフォルトはsqlite3)
2. Heroku CLI インストール
Herokuをコマンドラインで使用するために必要
下記URLを参考にしてください
https://qiita.com/karlley/items/c423d02eee2292dab1f9
3. Heroku SSH鍵追加
/home/vagrant/.ssh
にSSH鍵があるか確認$ cd ~/.ssh $ ls -a authorized_keys
id_rsa
,id_rsa.pub
が無い場合はSSH鍵が無いので下記URLを参考に生成https://git-scm.com/book/ja/v1/Git-サーバー-SSH-公開鍵の作成
$ cd ~/.ssh $ ssh-keygen $ ls -a authorized_keys id_rsa id_rsa.pubSSH鍵が生成されたのでHerokuにログインし鍵を追加
Herokuアカウントが無い場合は下記URLから作成
HerokuアカウントのEmail,Passwordを入力しログイン
$ heroku login --interactive heroku: Enter your login credentials Email: Password:Herokuにログイン後、SSH鍵を追加
$ heroku keys:add Found an SSH public key at /home/vagrant/.ssh/id_rsa.pub ? Would you like to upload it to Heroku? Uploading /home/vagrant/.ssh/id_rsa.pub SSH key... doneHerokuにSSH鍵が追加されました
HerokuのアカウントページのSSH Keysで追加された鍵を確認できます4. デプロイ
Herokuにアプリケーションを作成
$ heroku create your-app-name Creating app... done, ⬢ your-app-name . .アプリ名が表示されアプリケーションが作成されます
リポジトリをプッシュ
$ git push heroku master . . remote: Verifying deploy... done. . . * [new branch] master -> masterデプロイ成功したのでブラウザで確認
$ heroku open . . ▸ Manually visit https://your-app-url/ in your browser.表示されたURLをブラウザで確認
無事「Hello world!」できました!
あっさり進んでいるように見えますが私のようなプログラミング初心者にとってローカル環境からデプロイするのは一つの大きな壁でした汗
同じように悩んでいる方に少しでも参考になればと思います!
- 投稿日:2019-10-08T01:28:12+09:00
RuboCop 0.75で導入された --disable-uncorrectable で、指摘を無視しつつTODOコメントに置き換える
はじめに
RuboCop 0.75 が、2019/10/01にリリースされました。
その中でも
--disable-uncorrectable
という、--auto-correct
と合わせて付与するオプションが追加されました。本記事ではそちらについて紹介したいと思います。
--auto-correct
とは
--disable-uncorrectable
は、--auto-correct
とセットで使われるため、一応そちらについても触れておきます。例えば以下のようなスタイルの崩れたコードは、rubocop実行時に指摘を受けます。
sample.rbdef hoge { a: 1, b: 2 } end$ rubocop sample.rb Inspecting 1 file C Offenses: sample.rb:6:7: C: Layout/AlignHash: Align the elements of a hash literal if they span more than one line. b: 1 ^^^^ 1 file inspected, 1 offense detectedその際、
--auto-correct
というオプションをつけてrubocopを実行するとrubocopが自動で修正できる範囲で勝手に修正してくれるという機能です。$ rubocop sample.rb --auto-correct Inspecting 1 file C Offenses: sample.rb:6:7: C: [Corrected] Layout/AlignHash: Align the elements of a hash literal if they span more than one line. b: 1 ^^^^ 1 file inspected, 1 offense detected, 1 offense correctedsample.rbdef hoge { a: 1, b: 1 } end
--disable-uncorrectable
とは
--disable-uncorrectable
は、--auto-correct
によって自動修正できなかった違反について、TODOコメントを付与して、以降指摘が発生しないようにする機能です。例えば以下のコードは、メソッドの行数違反でありますが、rubocopが勝手に行数を減らすような自動修正をかけることはできません。
sample.rbdef hoge fuga fuga fuga fuga fuga fuga fuga fuga fuga fuga fuga end$ rubocop --auto-correct sample.rb Inspecting 1 file C Offenses: sample.rb:3:1: C: Metrics/MethodLength: Method has too many lines. [11/10] def hoge ... ^^^^^^^^ 1 file inspected, 1 offense detectedそんなときは、
--disable-uncorrectable
をあわせて付与すると、以下のようにTODOコメントを付与して、指摘を部分的に無効にしてくれます。$ rubocop --auto-correct --disable-uncorrectable sample.rb Inspecting 1 file C Offenses: sample.rb:3:1: C: [Todo] Metrics/MethodLength: Method has too many lines. [11/10] def hoge ... ^^^^^^^^ 1 file inspected, 1 offense detected, 1 offense correctedsample.rbdef hoge # rubocop:todo Metrics/MethodLength fuga fuga fuga fuga fuga fuga fuga fuga fuga fuga fuga endこれによって、
hoge
メソッドに対してはMetrics/MethodLength
の指摘が行われなくなるので、以降では新たに発生した違反についてのみ指摘を受けることになります。$ rubocop sample.rb Inspecting 1 file . 1 file inspected, no offenses detected補足
--auto-correct
は-a
で置き換えることも可能です--ignore-disable-comments
を付けた場合は、コメントがついてても容赦なく指摘されます- 部分的な指摘無視コメントはもちろん手動でも入れられますし、以前のバージョンからあった仕組みです
- 無視コメント入れただけの対応を続けると本末転倒なのでちゃんと治そうね
- 投稿日:2019-10-08T01:28:12+09:00
RuboCop 0.75で導入された --disable-uncorrectable で、指摘/警告を無視しつつTODOコメントに置き換える
はじめに
RuboCop 0.75 が、2019/10/01にリリースされました。
その中でも
--disable-uncorrectable
という、--auto-correct
と合わせて付与するオプションが追加されました。本記事ではそちらについて紹介したいと思います。
--auto-correct
とは
--disable-uncorrectable
は、--auto-correct
とセットで使われるため、一応そちらについても触れておきます。例えば以下のようなスタイルの崩れたコードは、rubocop実行時に指摘(警告)を受けます。
sample.rbdef hoge { a: 1, b: 2 } end$ rubocop sample.rb Inspecting 1 file C Offenses: sample.rb:6:7: C: Layout/AlignHash: Align the elements of a hash literal if they span more than one line. b: 1 ^^^^ 1 file inspected, 1 offense detectedその際、
--auto-correct
というオプションをつけてrubocopを実行するとrubocopが自動で修正できる範囲で勝手に修正してくれるという機能です。$ rubocop sample.rb --auto-correct Inspecting 1 file C Offenses: sample.rb:6:7: C: [Corrected] Layout/AlignHash: Align the elements of a hash literal if they span more than one line. b: 1 ^^^^ 1 file inspected, 1 offense detected, 1 offense correctedsample.rbdef hoge { a: 1, b: 1 } end
--disable-uncorrectable
とは
--disable-uncorrectable
は、--auto-correct
によって自動修正できなかった違反について、TODOコメントを付与して、以降指摘が発生しないようにする機能です。例えば以下のコードは、メソッドの行数違反でありますが、rubocopが勝手に行数を減らすような自動修正をかけることはできません。
sample.rbdef hoge fuga fuga fuga fuga fuga fuga fuga fuga fuga fuga fuga end$ rubocop --auto-correct sample.rb Inspecting 1 file C Offenses: sample.rb:3:1: C: Metrics/MethodLength: Method has too many lines. [11/10] def hoge ... ^^^^^^^^ 1 file inspected, 1 offense detectedそんなときは、
--disable-uncorrectable
をあわせて付与すると、以下のようにTODOコメントを付与して、指摘を部分的に無効にしてくれます。$ rubocop --auto-correct --disable-uncorrectable sample.rb Inspecting 1 file C Offenses: sample.rb:3:1: C: [Todo] Metrics/MethodLength: Method has too many lines. [11/10] def hoge ... ^^^^^^^^ 1 file inspected, 1 offense detected, 1 offense correctedsample.rbdef hoge # rubocop:todo Metrics/MethodLength fuga fuga fuga fuga fuga fuga fuga fuga fuga fuga fuga endこれによって、
hoge
メソッドに対してはMetrics/MethodLength
の指摘が行われなくなるので、以降では新たに発生した違反についてのみ指摘を受けることになります。$ rubocop sample.rb Inspecting 1 file . 1 file inspected, no offenses detected補足
- 近い機能で、
--auto-gen-config
というオプションもあり、こちらはTODOリストをyamlファイルに書き出します--auto-correct
は-a
で置き換えることも可能です--ignore-disable-comments
を付けた場合は、コメントがついてても容赦なく指摘されます- 部分的な指摘無視コメントはもちろん手動でも入れられますし、以前のバージョンからあった仕組みです
- 無視コメント入れただけの対応を続けると本末転倒なのでちゃんと治そうね
- 投稿日:2019-10-08T00:16:22+09:00
【48日目】【技術日記】コメント機能の作成 アソシエーションとかパーシャルとか
ここ数日は新しくお願いしたメンターさんとの面談や、
そのメンタリングの中で出された課題などを行なっていたので技術に触れていなかったため更新中断しておりました。
今日からまた技術の学習を進めていきます。なお今日はトピックというよりは、学習ログの掲載という感じになります。
主にアソシエーションの設定であったり、掲示板のコメントフォームのパーシャルの作成部分になります。
コメントフォームはviewを持たないので、親であるboardと紐づいた形で、@commentを作るところなんかが自分では思いつけない部分だと思いました。
まだ完璧に理解できていないと思います。65 Commentモデルの作成とアソシエーション
Commentモデルの作成
Commentモデルのマイグレーションファイルを作成
docker-compose exec web bundle exec rails g model comment board:references name:strings comment:text # rails g model モデル名 親テーブル名:references カラム名:型 # referencesによって「親テーブル名_id」という外部キーカラムが作成され、アソシエーションされる出来上がったマイグレーションファイルは下記
comments.rbclass CreateComments < ActiveRecord::Migration[5.0] def change create_table :comments do |t| t.references :board, foreign_key: true # 引数によって親テーブルにないidが保存できなくなる t.string :name, null: false #引数によってnullの場合エラーとなる t.text :comment, null: false t.timestamps end end endマイグレートを実行し、DBにマイグレーション内容を反映
docker-compose exec web bundle exec rake db:migrateアソシエーションの設定
親テーブル
ApplicationRecordのクラス継承の下に
board.rbhas_many :comments #1対他のためhas_many:子テーブル名(複数形)子テーブル
comments.rbbelongs_to :board66 コメント書き込み機能のルーティング追加 &コントローラ作成
コメントコントローラの作成
コメント機能には作成と削除のみを付与する。
また、コメントページは用意せず、掲示板のshowの下部に表示する。docker-compose exec web rails g controller comments create destroy --skip-template-engine # viewの作成をskipするルーティングの修正
rails g によって自動的にルーティングされるが、リソースベースルーティングに合わせて修正する。
routes.rbRails.application.routes.draw do # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html resources :boards resources :comments, only: %i[create destroy] endコメントオブジェクトの作成
form_forヘルパーでコメントのフォームを作成するために、board_controllerのshowメソッドで@commentオブジェクトを作成する。
ただし、何かしらの方法で掲示板とコメントを紐付ける必要がある。boards_controller.rbdef show @comment = @board.comments.new binding.pry endboardオブジェクトのcommentにnew メソッドを呼び出すことで掲示板に紐ついた@commentが作成できる。
binding.pryで@board.commentsの中を見ておく。
ちなみにこのオブジェクトのクラスはComment::ActiveRecord_Associations_CollectionProxy67 コメントフォームの作成
show の修正
パーシャルを用いて作成
show.html.erb<%= render 'boards/detail', detail: @detail %> <%= render partial: 'comment_form', locals: { comment: @comment} %> # commentというローカル変数で@commentのオブジェクトを渡すようにしているパーシャルの作成
_comments_form.html.erb<div class="p-comment__formBox"> <p class="p-comment__formTitle">コメント記入</p> <%= form_for comment do |f| %> <%= f.hidden_field :board_id %> # フォームの内容と一緒に外部キーを渡すために必要になる # フォーム自体は存在しない <div class="form-group"> <%= f.label :name, '名前' %> <%= f.text_field :name, class: 'form-control' %> </div> <div class="form-group"> <%= f.label :comment, 'コメント' %> <%= f.text_area :comment, class: 'form-control', rows: 4 %> </div> <%= f.submit '送信', class: 'btn btn-primary' %> <% end %> </div>CSSの作成
comments.scss.p-comment__formBox { margin: 30px auto; border: 5px solid #e8e8e8; padding: 25px; border-radius: 14px; } .p-comment__formTitle { border-bottom: 2px solid #dfdfdf; padding-bottom: 5px; }これだけでは読み込まれないので、application.scssでインポートするよう追記
applocateion.scss@import "comments"68 コメント保存処理の実装
rails-flogの導入
binding.pryのログを見やすくしてくれるらしい。
明日から使っていくことになる。gem 'rails-flog', require 'flog'
- 投稿日:2019-10-08T00:14:52+09:00
attr_encryptedなカラムを検索する方法
初めまして、ガッシーです。Qiita初投稿となります。(なんか癖でQuiitaって打っちゃうんですよね)
日頃Railsの開発で躓いて調べたことなどを書き留めていければなと思ってます。
そんなところで本題へ。railsでカラムを暗号化する際には一般的にattr_encryptedを利用するかと思いますが
READMEを翻訳しますと暗号化されたデータを検索することはできません。検索できないため、インデックスを作成することもできません。
との記載があります。
でも暗号化しつつ検索したいことって結構あると思うんですよね。そこで登場するGemがblind_indexです。
ただし LIKE検索はできない ので注意してください。blind_indexとは
例えばnameというカラムでattr_encryptedを使うときは
encrypted_name
とencrypted_name_iv
の2つのカラムを用意すると思いますが、
それに加えてencrypted_name_bidx
というカラムを追加してあげることで、そこに検索できる値を保存する感じです。早速やってみましょう。設定
READMEに書いてあることをそのままやっていけばいいのですが一応書きます。
Gemfileに下記を追加してbundle install
gem 'blind_index'コンソールを起動して下記コードを実行しランダムなキーを取得します。
irb(main):001:0> BlindIndex.generate_key # SecureRandom.hex(32).force_encoding(Encoding::US_ASCII) でも同じ => "222189cbba7ba0381c66faf8f687197b4bd4256a99bf81c917256c2871ca5289"キーを保存・設定します。
credentials.yml.encblind_index_master_key: "222189cbba7ba0381c66faf8f687197b4bd4256a99bf81c917256c2871ca5289"config/initializers/blind_index.rbBlindIndex.master_key = Rails.application.credentials.blind_index_master_key(initializerを読み込むためサーバーは再起動しておいてください)
blind_index用のカラムを追加します。
db/migrate/add_name_bidx_to_users.rbadd_column :users, :encrypted_name_bidx, :stringmodelも変更を加えます。
app/models/user.rbclass User < ApplicationRecord attr_encrypted :name, key: Rails.application.credentials.encrypted_key blind_index :name_bidx, key: Rails.application.credentials.blind_index_master_key #←こちら追加 end以上で設定は完了です!
※既に暗号化カラムが保存されている方はコンソールにて下記コマンドを実行することで既存のレコードにも対応できます。
User.unscoped.where(encrypted_name_bidx: nil).find_each do |user| user.compute_name_bidx user.save(validate: false) end実行
User.where(name: "山田太郎")これができるようになっているはずです。
感想
完全一致検索しかできないけど何もできないよりはマシか・・・
知識がないのですが、最初こちらの記事 attr_encryptedされたカラムに対してwhere likeしたかった。を見ましたが恐らく現在ivカラムを利用した暗号化を行っている場合は適応できないかな?と思ってます。
Qiita初めての記事となりましたのでもし誤りがありましたらご指摘いただければ幸いです。