- 投稿日:2020-04-07T22:25:25+09:00
Rails コマンドが急に使えなくなった
久しぶりにrailsを起動しようとしたらrails sが通りませでした。
同じくrails -vやrails newをしても同じ様な状態になります。色々調べたのですが、どうしても解決できずにこちらで質問させていただきます、、、
(初心者です、質問の仕方が間違っていたらすみません)
dlopen(/Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/2.5.0/x86_64-darwin18/digest/md5.bundle, 9): Library not loaded: /usr/local/opt/openssl/lib/libssl.1.0.0.dylib (LoadError)
Referenced from: /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/2.5.0/x86_64-darwin18/digest/md5.bundle
Reason: image not found - /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/2.5.0/x86_64-darwin18/digest/md5.bundlerails sを打つと色々出てきますが、最後にこの様な文があります、、
rails newやrails -vを打っても同じ様な症状です。
自分ではどうすることもできず
初歩的な質問かもしれませんが、どなたかお助けいただけませんでしょうか??、
よろしくお願いします。気になる事といえば
最近仮想開発環境を構築するのにVirtualBoxやvagrantを設定しました。
- 投稿日:2020-04-07T22:23:24+09:00
開発環境、テスト環境、本番環境って何?雑にメモ
3つの環境が用意されているよ
例えば、herokuにpushする場合は、本番環境を使用しているみたい
こいつらは、RAILS_ENVという環境変数を用いて動作モードを切り替えられる
例えば、コマンドプロンプトで普通に指令を送る場合は、開発環境に送っている。
じゃあ「本番環境」を指定して実行したい時は、、、
このコードを記述すればおk
RAILS_ENV=production
- 投稿日:2020-04-07T22:04:15+09:00
Kinx ライブラリ - Integer
Integer
はじめに
「見た目は JavaScript、頭脳(中身)は Ruby、(安定感は AC/DC)」 でお届けしているスクリプト言語 Kinx。言語はライブラリが命。ということでライブラリの使い方編。
リポジトリ(https://github.com/Kray-G/kinx) のほうの説明を "Looks like JavaScript, feels like Ruby, and it is the script language fitting in C programmers." に変えてみた。意味的には例の名探偵のオマージュですが、英語の表現は違っていてオリジナルです。
今回は Integer です。
- 参考
- 最初の動機 ... スクリプト言語 KINX(ご紹介)
- 個別記事へのリンクは全てここに集約してあります。
- リポジトリ ... https://github.com/Kray-G/kinx
- Pull Request 等お待ちしております。
Integer オブジェクトに括り付いたメソッドは特殊メソッドで、整数値に直接作用させることができる。特殊メソッド、および特殊オブジェクトに関する詳細は Kinx ライブラリ - String を参照してください。
Integer 特殊オブジェクト
Integer オブジェクトに対して関数定義する例は以下の通り。
Integer.times100 = function(value) { return value * 100; }; var val = 100.times100(); System.println(val);実行してみよう。
10000レシーバーが第 1 引数に来ます。
Integer
組み込み特殊メソッド
メソッド 意味 Integer.times(val, callback) i = 0 ~ (val - 1) の範囲として、 callback
があればcallback(i)
の結果で、無ければ i で配列を作成して返す。Integer.upto(val, max, callback) i = val ~ max の範囲で引数として callback(i)
を呼ぶ。Integer.downto(val, min, callback) i = min ~ val の範囲で引数として callback(i)
を呼ぶ。Integer.toString(val, base) val
を文字列に変換する。base
は 10 と 16 のみサポート。Integer.toDouble(val) val
を Double に変換する。Math オブジェクト・メソッド
Integer オブジェクトには Math オブジェクトと同じ特殊メソッドが存在する。詳細は以下を参照。
具体例で書くと、例えば以下のように書ける。
var a = 2.pow(10); // Math.pow(2, 10) と同じ => 1024 var b = (-10).abs(); // Math.abs(-10) と同じ => 10単項マイナス(
-
)は関数呼び出しより優先順位が低いため、カッコで括る必要があることに注意。特殊オペレーター
単項
*
オペレーター単項
*
オペレーターを整数値に適用した場合、文字コードに対応した文字列(1 文字)を返す。var a = *97; // => "a"ちなみに逆変換(
*a
)は元に戻らない。文字列に対する単項*
オペレーターは配列になるため、上記例で*a
とすると[97]
と配列となることに注意。単独で文字コードを得るには、a[0]
とする。おわりに
Integer に特殊メソッドがあることでグッと Ruby っぽい感じがしてますが気のせいですかね。
2.pow(10)
とか書けるのが結構感慨深いなー。ここ 見ながら、今サポートしてないメソッドとかサポートしてみようかなー、と。
ではまた次回。
- 投稿日:2020-04-07T21:48:50+09:00
配列とハッシュに関して
対象読者
プログラミング初学者
配列に関して
配列(array)は複数の値をまとめて管理したいときに使用する。
配列内で管理されるものは”要素(element)”と呼ばれる。配列の定義のしかた
#例1 array = Array.new #例2 fruits = ["apple", "banana"]配列に要素を追加する方法
型は以下の通り。
配列.push(追加する要素)例えば
#空の配列を用意して array = Array.new #"A"を追加するには array.push("A") puts array # 出力結果 ["A"]また、一度に複数の要素を追加したい時は
#先ほどの配列をそのまま適用すると array.push("B", "C") puts array # 出力結果 ["A", "B", "C"]要素の間に要素を追加(挿入)する方法
型は以下の通り。
配列.insert(挿入位置, 挿入する要素)例えば
#以下の配列があったとして array = ["A", "B", "D"] #"C"を挿入する場合は array.insert(2, "C") puts array # 出力結果 ["A", "B", "C", "D"]また、一度に複数の要素を挿入したい時は、第3引数以降に要素を渡す。
#先ほどの配列をそのまま適用すると array.insert(2, 1, 2) puts array # 出力結果 ["A", "B", 1, 2, "C", "D"]配列内の要素を削除する方法
型は以下の通り。
配列.delete(削除する要素)例えば
#以下の配列があったとして array = ["A", "B", 1, 1, 2, "C", "D"] #1を削除するには array.delete(1) puts array # 出力結果 ["A", "B", 2, "C", "D"]()内の引数に渡した要素と一致するものをすべて配列から削除する。
指定位置の要素を削除する方法
型は以下の通り。
配列.delete_at(削除位置)例えば
#以下の配列があったとして array = ["A", "B", 2, "C", "D"] #2を削除するには array.delete_at(2) puts array # 出力結果 ["A", "B", "C", "D"]指定範囲の要素を削除する方法
型は以下の通り。
配列.slice!(削除開始位置, 削除する長さ)例えば
#以下の配列があったとして array = ["A", "B", 1, 1, 2, "C", "D"] #1,1,2を削除するには array.slice!(2, 3) # 出力結果 ["A", "B", "C", "D"] #または array.slice!(2..4) #上記の型は 配列.slice!(削除範囲)配列の中の要素を取り出す方法
型は以下の通り。
array[要素番号]例えば
#以下の配列があったとして array = ["A", "B", "C", "D"] # "A"を取得するには puts array[0] # 出力結果 "A"ハッシュに関して
キーとバリュー(値)を組み合わせて保持するデータ構造のこと。
配列は一つの要素にオブジェクトが一つ入っていたのに対して、ハッシュはオブジェクトがキーとバリューの二つ入っている。ハッシュの定義のしかた
#例1 hash = Hash.new #例2 user = {user1: "たけし", user2: "たかし"}要素を追加する方法
型は以下の通り。
ハッシュ[追加したい要素のキー] = 値例えば
#以下の配列があったとして users = {user1: "たけし", user2: "たかし"} # キーがuser3、バリューがけんじの要素を追加するには users[:user3] = "けんじ" puts users # 出力結果 {:user1=>"たけし", :user2=>"たかし", :user3=>"けんじ"}そのほかの追加の方法としては、以下があります。
ハッシュ.store(追加したい要素のキー, 値)具体例は以下の通り。
#以下の配列があったとして users = {user1: "たけし", user2: "たかし"} # キーがuser3、バリューがけんじの要素を追加するには users.store("user3", "けんじ") puts users # 出力結果 {:user1=>"たけし", :user2=>"たかし", :user3=>"けんじ"}要素を削除する方法
型は以下の通り。
ハッシュ.delete(削除したい要素のキー)例えば
#以下の配列があったとして users = {:user1=>"たけし", :user2=>"たかし", :user3=>"けんじ"} # キーがuser3、バリューがけんじの要素を削除するには users.delete("user3") puts users # 出力結果 {:user1=>"たけし", :user2=>"たかし"}値が(キーと一緒に)ハッシュから取り除かれる。
ハッシュの中の特定のバリューを取得する方法
型は以下の通り。
ハッシュオブジェクト[:キー名]例えば
#以下の配列があったとして users = {:user1=>"たけし", :user2=>"たかし"} # "たかし"を取り出す時は puts users[:user2]ハッシュの中のバリュー一覧を取得する方法
例えば
#以下の配列があったとして users = {:user1=>"たけし", :user2=>"たかし"} puts users.values # 出力結果 たけし, たかしハッシュの中のキー一覧を取得する方法
例えば
#以下の配列があったとして users = {:user1=>"たけし", :user2=>"たかし"} puts users.keys # 出力結果 [:user1, :user2]問題
配列の内部に、複数のユーザーの情報をハッシュとして持つ変数user_dataがある。
user_dataを利用して、全てのユーザーの名前だけが出力されるようにRubyでコーディングしてください。user_data = [ {user: {profile: {name: 'George'}}}, {user: {profile: {name: 'Alice'}}}, {user: {profile: {name: 'Taro'}}} ]解答
user_data.each do |u| puts u[:user][:profile][:name] end #または user_data.each{ |u| puts u.dig(:user, :profile, :name) }
- 投稿日:2020-04-07T21:13:52+09:00
クロスサイトリクエストフォージェリ(CSRF)の対策
クロスサイトリクエストフォージェリ(CSRF)
Webサイトにスクリプトや自動転送(HTTPリダイレクト)を仕込むことによって、利用者に意図せず別のWebサイト上で何らかの操作(掲示板への書き込みや銀行口座への送金など)を行わせる攻撃手法のことをいいます。
CSRFの脆弱性が存在すると以下のような被害を被る可能性があります。
①利用者のアカウントによる物品の購入
②利用者の退会処理
③利用者のアカウントによる掲示板への書き込み
④利用者のパスワードやメールアドレスが変更
CSRF脆弱性の影響は「重要な処理」の悪用に限られるため、CSRFの脆弱性を個人情報の取得等に用いることはできません。CSRFの攻撃例
例えば、利用者が罠サイトを閲覧することによってパスワードが変更されてしまう場合
①利用者がexample.jpにログインしている
②攻撃者は罠を作成
③利用者が罠を閲覧する
④罠のJavaScriptによる、被害者のブラウザ上で攻撃対象サイトに対し、新しいパスワードabcdefがPOSTメソッドにより送信される
⑤パスワードが変更されるCSRFの対策
CSRF攻撃を防ぐには、「重要な処理」に対するリクエストが利用者の意図によるものかどうかを確認することが必要になります。
このためCSRF対策が以下の2点です。
①CSRF対策の必要なページを区別する
②正規利用者の意図したリクエストを区別できるように実装するCSRF対策の必要なページを区別する
CSRF対策はすべてのページに行う必要はありません。対策に必要なページは、他のサイトから勝手に実行されては困るようなページです。例えば、ECサイトの物品購入ページや、パスワード変更など個人情報の編集確定画面などです。
CSRFの対策としては、まず実装するWebアプリケーションのどのページに脆弱性対策が必要なのか設計段階で明らかにすることです。
例えば、機能一覧を紙に記入し、CSRFの対策が必要なページを色分けすると良いと思います。
商品ページ=>認証=>カートに追加=>購入確認=>購入確定
この中だと最後の購入確定がCSRFの対策が必要です。正規利用者の意図したリクエストを区別できるように実装
CSRF対策で必要なことは、正規利用者の意図したリクエストなのかどうかということです。
意図したリクエストとは、利用者が対象のアプリケーション上で「実行」ボタンなどを押して、「重要な処理」のリクエストを発行することです。
正規のリクエストかどうかを判断する方法は3種類あります。
①秘密情報の埋め込み
②パスワードの再入力
③Refererのチェック秘密情報の埋め込み
登録画面や注文確定画面などのCSRF攻撃への対策が必要なページに対して、第三者の不正利用者が知り得ない秘密情報を要求するようにすれば、不正リクエストによる重要な処理が実行されることはありません。このような目的で使用される秘密情報のことをトークンといいます。
パスワードの再入力
こちらは文字通り重要な処理が確定する前に、再度パスワードを入力してもらいます。これはCSRF対策の他にも物品の購入などに先立って、利用者の意思の念押しをしたり、共用のPCにおいて正規の利用者以外の利用者が、重要な処理を実行するのを防いだりする効果があります。
CSRFの攻撃例として、とりあげたパスワード変更ページにも現在のパスワードを再入力させることによりCSRF攻撃を防ぐことが可能です。RailsでのCSRF対策方法
Rails側できちんと対策を行ってくれています。基本的には開発者はなにもしなくても大丈夫です。
例として、RailsでのCSRF対策app/controllers/application_controller.rbclass ApplicationController < ActionController::Base # Prevent CSRF attacks by raising an exception. # For APIs, you may want to use :null_session instead. protect_from_forgery with: :exception #追加部分 before_action :configure_permitted_parameters, if: :devise_controller? def configure_permitted_parameters devise_parameter_sanitizer.for(:sign_up) << :nickname end endprotect_from_forgery with: :exception
これがRailsアプリケーション内でCSRF対策を行うというという命令になります。こちらをすべてのコントローラの親であるapplication_controller.rbに記述することによって、その子コントローラすべてに先ほど説明したようなCSRF対策をRails側で行ってくれます。
具体的には、まずサイトのHTMLに一意のトークンを埋め込みます。これと同じトークンを、セッションcookie(クッキー)にも保存しています。ユーザーがPOSTリクエストを送信すると、HTMLに埋められているCSRFトークンも一緒に送信されます。あとは、サーバ側でページのトークンとセッション内のトークンを比較し、両者が一致することを確認したらリクエストを受け付けます。
- 投稿日:2020-04-07T21:01:23+09:00
gRPC: prototoolからbufへの道 ~ vol. 1 ~
gRPC: prototoolからbufへの道 ~ vol. 1 ~
Bufとは
Protobufが技術的なメリットの良い選択になるだけでなく、非常に使いやすく決定が簡単になることです
機能
- 自動ファイル検出
- prototoolとは違い、任意に指定も可能
- 正確なlintとbreaking checkersの構成が選択可能になる
- lint: 40 breaking checkers: 50
- エラー出力はどのエディターでも簡単に解析可能
- コンパイルの高速化
- protoc: 4.3sに対して 4コアでbuf: 0.8s
- protocのプロトコルプラグインとして使用
Buf CLIツール
サポートされている機能
- 優れたAPI設計の選択と構造を強制するリンター
- ソースコードまたはワイヤレベルでの互換性を強制する重大な変更検出器
- FileDescriptorSetsの拡張機能であるイメージを生成する構成可能なファイルビルダー
インストール方法
brew tap bufbuild/buf brew install buf使い方は次回紹介します
- 投稿日:2020-04-07T20:31:58+09:00
ユーザーの役割を分ける際はSQLアンチパターンを意識する
●はじめに
Railsチュートリアルを参考にしポートフォリオを作成すると、Userモデルにadmin属性を追加しSTIで管理ユーザーを作成する事になるかと思います。
しかし、SQL的にはアンチパターンであるため注意が必要です。●結論
Userモデルと別に、adminモデルを作成する事が良い。
●STI(Single Table Inheritance:単一テーブル継承)
STIは、単一の継承階層に所属するクラス群を、ひとつのテーブルを使って永続化する手法です。
このように実装する方法ですね。しかしこの方法はSQL的にアンチパターンだという事です。
なぜこの方法が良くないかという点は、下記URLを参考にしました。
https://qiita.com/yebihara/items/9ecb838893ad99be0561短所
・特定のサブクラスに固有の属性に対してNOT NULL制約を適用できない
・特定のサブクラスのみを参照すべき他テーブルの外部キー制約が、誤ったサブクラスを参照することを防げない
・テーブルのカラム数が多くなりやすい
・一部のサブクラスでしか使われない列の値はNULLばかりとなり、見た目がスパースになる●まとめ
データベース設計時には、アンチパターンを意識する必要がある。
Rails初学者にとってSQLやDBは苦手意識を持ちやすい所だと思います(自分がそうです)
だからこそポートフォリオ作成前にはしっかりとデータベース設計をし、ER図を作成し、メンターに確認をして頂いた後に実装を進めることをオススメします。
- 投稿日:2020-04-07T16:20:25+09:00
クロスサイトスクリプティング(XXS)対策
クロスサイトスクリプティング(XXS)
Webアプリケーションでは、外部からの入力などに応じて表示が変化するページを実装したいことがしばしばあります。
しかし、この部分のHTML生成の実装に問題があると、外部よりスクリプトを埋め込まれクッキーを盗まれたり、JavaScriptによる攻撃を受けてしまうおそれがあります。
こういった攻撃手法をクロスサイトスクリプティングと言います。XSSの攻撃例
では、実際にXSSの脆弱性を用いた攻撃例です。
ここでは登場人物を用いて説明します。
ユウスケ・・・ 一般ユーザ
タカシ ・・・攻撃を仕掛ける悪意のある者
1. タカシはXSSの脆弱性があるサイトに悪意のあるスクリプトを埋め込む
2. タカシは1.でスクリプトを埋め込んだサイトをリンクに指定する罠サイトを用意する
3. タカシはユウスケに罠サイトへ誘導するようなメールを送信する
4. ユウスケは罠サイトにアクセスし、タカシがスクリプトを埋め込んだサイトにアクセス
5. ユウスケのブラウザ上でタカシが埋め込んだスクリプトが実行される
※ここで出てくる罠サイトとは、スクリプトを埋め込んだXSSの脆弱性のあるサイトへのリンクを含んでいるページのことをいいます。
ここで実行されるスクリプトの例としては、cookieを攻撃者のサーバに送信されてしまったり、マルウェア(悪意のあるソフトウェア)を仕込んであるサイトにリダイレクトされウイルスに感染させられたりとJavascriptで記述することが可能なすべての攻撃を受けてしまう可能性があります。XSSの対策
XSSが発生する主要因として、フォームから入力されたHTMLタグがそのままページに反映されてしまっていることがあげられます。
したがって、XSSを防ぐためにはHTMLを生成する際に意味を持つ「"」や「<」を文字参照によってエスケープすることが基本となります。文字参照
HTML上で直接記述できない特殊文字を表記する際に用いられる記法です。例えば、HTML中に「<」もしくは「>」と記述するとこの二つはタグの初め、終わりと認識されてしまいます。これでは文字列として上記の記号を用いることができません。そこで、文字参照を利用します。
変換前 変換後 < & lt; > & gt; & & amp; " & quot; ' & #39; 上の表は、XSSを対策する際にエスケープすべき特殊文字の一覧です。これらの特殊文字を文字参照に変換して保存すれば、外部から埋め込まれたスクリプトが実行されることはありません。
rawメソッド
文字列を文字参照にエスケープしないためのヘルパーメソッドです。
【例】raw(文字列)<%= raw(tweet.text) %>
- 投稿日:2020-04-07T16:02:18+09:00
each文の基本1
環境,前提
Ruby 2.5.1
MacOS Mojave Ver.10.14.6本記事はRubyがインストールされた前提の記事です。
Rubyをインストールしたあと、とにかくRubyをいろいろ触ってみて慣れていくための記事です。お役に立てば幸いです。eachメソッド
eachメソッドは配列や範囲オブジェクトで使用できるメソッドで、オブジェクトに含まれる要素を順番に取得することができます。基本的な書き方は以下のようになります。
sample.rb配列オブジェクト.each do |変数| #処理 end具体例で書きますと
sample.rbfruites = ["オレンジ", "イチゴ", "リンゴ"] fruites.each do |fruite| puts fruite end出力結果は以下のようになります。
Tarminaiオレンジ イチゴ リンゴ解説
まずソースコードの1行目でfruitesという配列オブジェクトを用意しています。
そして配列オブジェクトfruitesの要素(オレンジ、イチゴ、リンゴ)を順番に変数fruiteに代入し、putsで出力しています。
。配列の名前は複数形なのでfruites,eachメソッド内での変数は単数形のfruiteになっています。
また、eachメソッド内で使用したfruiteという変数は「ブロックパラメーター」と呼ばれています。
- 投稿日:2020-04-07T16:02:18+09:00
each文の基本
環境,前提
Ruby 2.5.1
MacOS Mojave Ver.10.14.6本記事はRubyがインストールされた前提の記事です。
Rubyをインストールしたあと、とにかくRubyをいろいろ触ってみて慣れていくための記事です。お役に立てば幸いです。eachメソッド
eachメソッドは配列や範囲オブジェクトで使用できるメソッドで、オブジェクトに含まれる要素を順番に取得することができます。基本的な書き方は以下のようになります。
sample.rb配列オブジェクト.each do |変数| #処理 end具体例で書きますと
sample.rbfruites = ["オレンジ", "イチゴ", "リンゴ"] fruites.each do |fruite| puts fruite end出力結果は以下のようになります。
Tarminaiオレンジ イチゴ リンゴ解説
まずソースコードの1行目でfruitesという配列オブジェクトを用意しています。
そして配列オブジェクトfruitesの要素(オレンジ、イチゴ、リンゴ)を順番に変数fruiteに代入し、putsで出力しています。
。配列の名前は複数形なのでfruites,eachメソッド内での変数は単数形のfruiteになっています。
また、eachメソッド内で使用したfruiteという変数は「ブロックパラメーター」と呼ばれています。
- 投稿日:2020-04-07T15:48:55+09:00
情報セキュリティとは
情報セキュリティ
Webサービスにおいてのセキュリティ(安全保障)です。情報セキュリティにおける理想は、「不正なアクセスや情報の漏洩を防ぎつつ、権限がある人は便利に利用できる」状態を維持することです。「機密性」「完全性」「可用性」の3つの要素を維持することを目標にします。
①機密性 権限を持たない人が情報資産を見たり使用できないようにすること
②完全性 権限を持たない人が情報を書き換えたり消したりできないようにすること
③可用性 権限を持つ人がいつでも利用したいときに利用できるようにすること脆弱性(ぜいじゃくせい)について
コンピュータやネットワーク、アプリケーション全体のセキュリティに弱点を作り出すコンピュータソフトウェアの欠陥や仕様上の問題点のことを脆弱性と言います。Webアプリケーションに脆弱性があると、開発者側だけでなく、利用者側も被害を被る可能性があり、様々な被害が生じる可能性があります。脆弱性は、バグや、開発者のセキュリティチェック不足により生まれます。
脆弱性によってもたらされる被害
脆弱性がアプリケーション内に存在することによって、以下のような被害が想定されます。
①個人情報を勝手に閲覧される(機密性侵害)
②Webページの内容が改ざんされる(完全性侵害)
③Webページ自体が利用不能になる(可用性侵害)
このような問題が起きてしまうと、利用者への金銭的損失の補填や補償、開発者の社会的信頼の失墜による売上の減少、Webサイト停止による機会損失など多くの被害をもたらすので脆弱性対策は必須です。脆弱性が生まれる理由
一つは、バグによるもの
二つ目は、開発者側のセキュリティチェック不足によるもの
ここでいうバグとは、クロスサイトスクリプティングのように投稿フォーム等にscriptタグでJavascriptのコードを記述・送信することで、それがページに埋め込まれ、実行されてしまうといったようなプログラミング言語の仕様に起因するものようなことを言います。クロスサイトスクリプティング(XSS)
Webサイトに利用されるアプリケーションの脆弱性もしくはその脆弱性を悪用した攻撃のことです。特にWeb閲覧者側が制作することのできる動的サイト(例:TwitterなどのSNS、掲示板等)に対して、その脆弱性を利用して悪意のある不正なスクリプトを挿入することによりその発生するサイバー攻撃です。
HTTP
HTTPとはWebブラウザとWebサーバの間でHTMLや画像ファイルなどのコンテンツの送受信に用いられる通信プロトコルです。Webページを閲覧・利用することができるのもHTTPという仕組みがあるからです。
プロトコル
複数のユーザが滞りなく信号やデータ、情報を相互に伝送できるよう、あらかじめ決められた約束事や手順の集合のことです。
例えば人と人との会話を例とすると、片方が日本語で話し、もう片方が中国語で話していては会話にならない状態です。
そこで、会話を成立させるためには使用言語をきちんと決める必要があります。この使用言語を何にするか決める役割が通信におけるプロトコルにあたります。
HTTPはクライアント(自分のパソコンなど)、ブラウザからのリクエストに対して、サーバからのレスポンスが返ってくることによって実現します。
例えば飲食店で考えたときに、料理を注文します。すると、お店側は注文された料理を提供します。
HTTPもこれと同じでクライアントが要求したページをサーバ側がクライアントに合わせて提供するという仕組みになっています。
例として、クライアントとサーバー間でHTTP通信を行う際はメッセージのやり取りを行います。
まず、クライアントからサーバーに対して以下のようなリクエストメッセージを送信します。
HTTPリクエスト GET / HTTP/1.1 リクエストライン Accept: image/gif, image/jpeg, / ヘッダ Accept-Language: ja Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0 (Compatible; MSIE 6.0; Windows NT 5.1;) Host: www.xxx.zzz Connection: Keep-Alive (空行) メッセージボディ(POSTメソッドなどで使用) www.xxx.zzz というアドレス
に対してHTTP/1.1というバージョンを使い、GETメソッドで"/"パスにアクセスしたい、というメッセージをクライアントからサーバに送っているいう意味になります。
それに対してサーバは以下のようなレスポンスメッセージを返します。
HTTPレスポンス HTTP/1.1 200 OK ステータスライン Date: Sun, 11 Jan 2004 16:06:23 GMT ヘッダ Server: Apache/1.3.22 (Unix) (Red-Hat/Linux) Last-Modified: Sun, 07 Dec 2003 12:34:18 GMT ETag: "1dba6-131b-3fd31e4a" Accept-Ranges: bytes Content-Length: 4891 Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Content-Type: text/html (空行) htmlやcssの情報(メッセージボディ) ステータスラインを見てみると先ほどのリクエストメッセージに対して、HTTP1.1/(バージョン)200(ステータス番号)OK(補足メッセージ)と返しています。
これは「HTTP/1.1というバージョン下でリクエストを受け付けました」という意味を表しています。ステータスコード
HTTP通信のレスポンスメッセージのステータスライン中にある3桁の数字で、クライアントからのリクエストに対して、サーバからの返
100の位に意味があり、そちらで分類されます。
ステータスコード 意味 100番台 処理が継続中 200番台 正常終了 300番台 リダイレクト 400番台 クライアント側でのエラー 500番台 サーバー側でのエラー よく使われるステータスコードとしては、200(正常終了)、301及び302(リダイレクト)、404(ファイルが存在しない)、500(内部サーバーエラー)などがあります。
セッション/クッキー(cookie)
HTTPは、ステートレスな通信となっています。
ステートレスとはサーバが現在の状態を保持せず、ユーザの入力の内容のみによって出力が決定される状態のことです。
例えば、ユーザのログイン状態やECサイトのカート機能などがあります。これらは、ページが遷移してもユーザの情報や購入しようとしている商品の情報を保持している必要があります。
こういった状態を保持するために用いられるのがセッションであり、HTTP通信のセッションを管理するために作られた仕組みをクッキー(cookie)といいます。このような通信をステートフル通信といいます。セッション
複数回に渡るリクエストにおいて、クライアントを特定するための仕組みです。具体的には、クライアントは初回のリクエストで自身を識別させるIDをサーバーに渡します。以降、サーバーはそのIDを持ってクライアントを認識します。
クッキー(cookie)
クライアント側のブラウザに保持することができる情報のことです。通常、初回の通信でサーバーがクライアントにクッキーとしてセッションIDを保持させ、以降クライアントはそれを用いてサーバーに対して自身を特定させます。
実際にクッキー(cookie)がどのように使われているか
まず、サーバー側で明示的にクッキー(cookie)を設定しますよ、という宣言をします。
Railsでは、session_store.rbというファイル内でセッションの管理方法を指定します。デフォルトでクッキー(cookie)を利用する設定になっているため、Railsでは意識せずクッキー(cookie)でのセッション管理を行うことができます。config/initializer/session_store.rbTechReviewSite::Application.config.session_store :cookie_store, key: '_tech_review_site_session'ログイン処理を例にとると、以下のような流れでクッキー(cookie)が利用されます。
①クライアントはログイン画面でIDとパスワードを入力する
②すると、サーバでクッキー(cookie)が生成され、クライアントが保持する
③次回以降アクセスする際に、クライアントが保持しているクッキー(cookie)がサーバに送信される
④サーバはこのクッキー(cookie)値を元にクライアントを識別し、ログイン作業を省く
まとめると
HTTPとはWebアプリケーションを利用する際にクライアントとサーバ間の情報をやり取りするための通信プロトコル
セッションとは、Webアプリケーション上で前のページの状態を保持するために利用される機能
- 投稿日:2020-04-07T13:47:31+09:00
環境構築から始めるテスト駆動開発 ~Ruby開発環境を構築する(WSL版)~
環境構築から始めるテスト駆動開発 ~Ruby開発環境を構築する(WSL版)~
はじめに
これは 環境構築から始めるテスト駆動開発 ~プログラミング環境の共通基盤を構築する~ の開発言語セットアップ記事です。Windows 10 Home で共通基盤が構築されていることを前提としています。
インストール
Ruby開発環境の自動構築をするため以下のレポジトリを自分のレポジトリにフォークします。
Fork
を押します。
Fork
が完了して自分のレポジトリにコピーされたらClone or download
を押してレポジトリのURLをコピーします。エクスプローラアイコンメニューから
レポジトリをクローンする
を押します。先程コピーしたレポジトリのURLを貼り付けます。
保存先はそのままで
OK
を押します。
開く
を押します。メニューから
ターミナル
新しいターミナル
を選択します。ターミナルに以下のコマンドを入力します。実行時にパスワード入力が求められるのでWSLで設定したパスワードを入力してください。
$ sudo apt-get update -y [sudo] password for newbie4649:続いて、ターミナルに以下のコマンドを入力します。
$ sudo apt install ansible -y続いて、エクスプローラから
provisioning/vars/site.yml
をファイルを開いてuser:
の名前をWSLで設定したユーザーIDに変更します。変更を保存したらターミナルに以下のコマンドを入力します。
$ cd provisioning/tasks/ $ sudo ansible-playbook --inventory=localhost, --connection=local site.ymlセットアップが完了したらエディタを再起動してプロジェクトを開きます。
以下のコマンドを入力してRubyがセットアップされていることを確認します。
$ ruby -v続いて、ターミナルに以下のコマンドを入力します。
$ code ~/.bashrc
表示されたファイルの一番最後に以下のコードを追加して保存します。
... export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_compl保存したら以下のコマンドを実行してNode.jsのバージョンが表示されたらセットアップ完了です。
$ source ~/.bashrc $ nvm install --lts $ node -v追加パッケージのインストール
ターミナルに以下のコマンドを入力します。
gem install rubocop gem install debase gem install ruby-debug-ide gem install solargraphHello world
プログラムを作成する
REAMD.md
を選択してから新しいファイル
作成アイコンを押します。ファイル名は
main.rb
とします。ファイルに以下のコードを入力したらRunアイコンを選択して
create a launch.json file
を押してメニューからRubyを選択します。require 'minitest/autorun' class TestHelloWorld < Minitest::Test def test_何か便利なもの assert_equal(true, false) end end
Debug Local File
を選択します。
launch.json
ファイルが作成されたらmain.rb
タブに戻ってF5キーを押します。デバッグコンソールに実行結果が表示されれば準備完了です。
テストをパスするようにコードを修正してF5キーを押します。
require 'minitest/autorun' class TestHelloWorld < Minitest::Test def test_何か便利なもの assert_equal(true, true) end endテスティングフレームワークの動作が確認できたので
hello_world
関数の作成に入ります。まず以下のコードを追加してF5キーを押してテストが失敗することを確認します。require 'minitest/autorun' class TestHelloWorld < Minitest::Test def test_何か便利なもの assert_equal(true, true) end def test_簡単な挨拶を返す assert_equal('Hello from Ruby', hello_world) end end
hello_world
関数を追加してテストをパスさせます。require 'minitest/autorun' class TestHelloWorld < Minitest::Test def test_何か便利なもの assert_equal(true, true) end def test_簡単な挨拶を返す assert_equal('Hello from Ruby', hello_world) end end def hello_world 'Hello from Ruby' end指定された名前で挨拶を返すようにします。
require 'minitest/autorun' class TestHelloWorld < Minitest::Test def test_何か便利なもの assert_equal(true, true) end def test_簡単な挨拶を返す assert_equal('Hello from Ruby', hello_world) end def test_指定された名前で挨拶を返す assert_equal('Hello from VSCode', hello_world('VSCode')) end end def hello_world "Hello from Ruby" end関数に引数を追加します。
require 'minitest/autorun' class TestHelloWorld < Minitest::Test def test_何か便利なもの assert_equal(true, true) end def test_簡単な挨拶を返す assert_equal('Hello from Ruby', hello_world) end def test_指定された名前で挨拶を返す assert_equal('Hello from VSCode', hello_world('VSCode')) end end def hello_world(name) "Hello from #{name}" end
指定された名前で挨拶を返す
テストはパスしましたが今度は簡単な挨拶を返す
テストが失敗するようになりましたのでデフォルト引数を設定してテストをパスするようにします。require 'minitest/autorun' class TestHelloWorld < Minitest::Test def test_何か便利なもの assert_equal(true, true) end def test_簡単な挨拶を返す assert_equal('Hello from Ruby', hello_world) end def test_指定された名前で挨拶を返す assert_equal('Hello from VSCode', hello_world('VSCode')) end end def hello_world(name = 'Ruby') "Hello from #{name}" end仕上げに不要なテストを削除してテストケースの文言をわかりやすくしておきます。
require 'minitest/autorun' class TestHelloWorld < Minitest::Test def test_何も指定されていない場合は既定の挨拶を返す assert_equal('Hello from Ruby', hello_world) end def test_指定された名前で挨拶を返す assert_equal('Hello from VSCode', hello_world('VSCode')) end end def hello_world(name = 'Ruby') "Hello from #{name}" endプログラムをデバッグする
まず確認したいプログラムの行を左部分を押してブレークポイント(赤丸)を設定します。
ブレークポイントを設定したらF5を押してプログラムの実行します。そうするとブレークポイント部分でプログラムが停止して変数などの情報が確認できるようになります。
画面上の実行ボタンを押すと次のブレークポイントに移動します。
デバッガを終了するには終了ボタンを押します。
ブレークポイントを再度押すことで解除ができます。
プログラムをレポジトリに保存する
全ての変更をステージ
を選択します。変更内容に
feat: HelloWorld
と入力してコミット
を押します。変更内容は
GitLens
から確認できます。
- 投稿日:2020-04-07T13:46:56+09:00
環境構築から始めるテスト駆動開発 ~Ruby開発環境を構築する~
環境構築から始めるテスト駆動開発 ~Ruby開発環境を構築する~
はじめに
これは 環境構築から始めるテスト駆動開発 ~プログラミング環境の共通基盤を構築する~ の開発言語セットアップ記事です。Windows 10 Home で共通基盤が構築されていることを前提としています。
インストール
RubyInstallerからWITH DEVKITをインストールします。
インストラーの指示に従います。
3を入力してエンターキーを押します。
追加パッケージのインストール
設定
既定のシェルをPowerShell Coreに変更します。
新しいターミナルを開いて以下のコマンドを入力します。
gem install rubocop gem install debase gem install ruby-debug-ide gem install solargraphHello world
プログラムを作成する
Projects
フォルダ内にRuby
フォルダを作成してエディタからフォルダを開きます。
新しいファイル
作成アイコンを押します。ファイル名は
main.rb
とします。ファイルに以下のコードを入力したらRunアイコンを選択して
create a launch.json file
を押してメニューからRubyを選択します。require 'minitest/autorun' class TestHelloWorld < Minitest::Test def test_何か便利なもの assert_equal(true, false) end end
Debug Local File
を選択します。
launch.json
ファイルが作成されたらmain.rb
タブに戻ってF5キーを押します。デバッグコンソールに実行結果が表示されれば準備完了です。
テストをパスするようにコードを修正してF5キーを押します。
require 'minitest/autorun' class TestHelloWorld < Minitest::Test def test_何か便利なもの assert_equal(true, true) end endテスティングフレームワークの動作が確認できたので
hello_world
関数の作成に入ります。まず以下のコードを追加してF5キーを押してテストが失敗することを確認します。require 'minitest/autorun' class TestHelloWorld < Minitest::Test def test_何か便利なもの assert_equal(true, true) end def test_簡単な挨拶を返す assert_equal('Hello from Ruby', hello_world) end end
hello_world
関数を追加してテストをパスさせます。require 'minitest/autorun' class TestHelloWorld < Minitest::Test def test_何か便利なもの assert_equal(true, true) end def test_簡単な挨拶を返す assert_equal('Hello from Ruby', hello_world) end end def hello_world 'Hello from Ruby' end指定された名前で挨拶を返すようにします。
require 'minitest/autorun' class TestHelloWorld < Minitest::Test def test_何か便利なもの assert_equal(true, true) end def test_簡単な挨拶を返す assert_equal('Hello from Ruby', hello_world) end def test_指定された名前で挨拶を返す assert_equal('Hello from VSCode', hello_world('VSCode')) end end def hello_world "Hello from Ruby" end関数に引数を追加します。
require 'minitest/autorun' class TestHelloWorld < Minitest::Test def test_何か便利なもの assert_equal(true, true) end def test_簡単な挨拶を返す assert_equal('Hello from Ruby', hello_world) end def test_指定された名前で挨拶を返す assert_equal('Hello from VSCode', hello_world('VSCode')) end end def hello_world(name) "Hello from #{name}" end
指定された名前で挨拶を返す
テストはパスしましたが今度は簡単な挨拶を返す
テストが失敗するようになりましたのでデフォルト引数を設定してテストをパスするようにします。require 'minitest/autorun' class TestHelloWorld < Minitest::Test def test_何か便利なもの assert_equal(true, true) end def test_簡単な挨拶を返す assert_equal('Hello from Ruby', hello_world) end def test_指定された名前で挨拶を返す assert_equal('Hello from VSCode', hello_world('VSCode')) end end def hello_world(name = 'Ruby') "Hello from #{name}" end仕上げに不要なテストを削除してテストケースの文言をわかりやすくしておきます。
require 'minitest/autorun' class TestHelloWorld < Minitest::Test def test_何も指定されていない場合は既定の挨拶を返す assert_equal('Hello from Ruby', hello_world) end def test_指定された名前で挨拶を返す assert_equal('Hello from VSCode', hello_world('VSCode')) end end def hello_world(name = 'Ruby') "Hello from #{name}" endプログラムをデバッグする
まず確認したいプログラムの行を左部分を押してブレークポイント(赤丸)を設定します。
ブレークポイントを設定したらF5を押してプログラムの実行します。そうするとブレークポイント部分でプログラムが停止して変数などの情報が確認できるようになります。
画面上の実行ボタンを押すと次のブレークポイントに移動します。
デバッガを終了するには終了ボタンを押します。
ブレークポイントを再度押すことで解除ができます。
プログラムをレポジトリに保存する
ソース管理を選択して
リポジトリを初期化する
を押します。
全ての変更をステージ
を選択します。変更内容に
feat: HelloWorld
と入力してコミット
を押します。変更内容は
GitLens
から確認できます。
- 投稿日:2020-04-07T12:07:57+09:00
【Rails】Ajaxを用いた非同期投稿の実装
目標
開発環境
・Ruby: 2.5.7
・Rails: 5.2.4
・Vagrant: 2.2.7
・VirtualBox: 6.1
・OS: macOS Catalina前提
ログイン機能を実装済み。
ログイン機能 ➡︎ https://qiita.com/matsubishi5/items/5bd8fdd45af955cf137d
投稿機能の実装
テーブル
schema.rbActiveRecord::Schema.define(version: 2020_04_05_115005) do create_table "books", force: :cascade do |t| t.string "title" t.text "body" t.integer "user_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false end create_table "users", force: :cascade do |t| t.string "email", default: "", null: false t.string "encrypted_password", default: "", null: false t.string "reset_password_token" t.datetime "reset_password_sent_at" t.datetime "remember_created_at" t.integer "sign_in_count", default: 0, null: false t.datetime "current_sign_in_at" t.datetime "last_sign_in_at" t.string "current_sign_in_ip" t.string "last_sign_in_ip" t.string "name" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["email"], name: "index_users_on_email", unique: true t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true end endモデル
user.rbclass User < ApplicationRecord has_many :books, dependent: :destroy endbook.rbclass Book < ApplicationRecord belongs_to :user endルーティング
routes.rbRails.application.routes.draw do devise_for :users resources :users resources :books endコントローラー
books.controll.rbclass BooksController < ApplicationController def create book = Book.new(book_params) book.user_id = current_user.id if book.save redirect_to book, notice: "successfully created book!" else @books = Book.all.order(created_at: :desc) #降順 render 'index' end end def index @book = Book.new @books = Book.all.order(created_at: :desc) #降順 end private def book_params params.require(:book).permit(:title, :body) end endビュー
books/index.html.erb<% if @book.errors.any? %> <h2><%= @book.errors.count %>error</h2> <div> <ul> <% @book.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div> <% end %> <%= form_with model: @book do |f| %> <div class="field row"> <%= f.label :title %> <%= f.text_field :title, class: "col-xs-12 book_title" %> </div> <div class="field row"> <%= f.label :body %> <%= f.text_area :body, class: "col-xs-12 book_body" %> </div> <div class="actions row"> <%= f.submit class: "btn btn-primary col-xs-12" %> </div> <% end %> <h2>Books index</h2> <table class="table table-hover table-inverse"> <thead> <tr> <th></th> <th>Title</th> <th>Opinion</th> </tr> </thead> <tbody> <% @books.each do |book| %> <tr> <td> <%= link_to book.user do %> <%= attachment_image_tag book.user, :profile_image, :fill, 50, 50, fallback: "no-image-mini.jpg" %> <% end %> </td> <td><%= link_to book.title, book %></td> <td><%= book.body %></td> </tr> <% end %> </tbody> </table>非同期機能の実装
1. jQueryの導入
Gemfilegem 'jquery-rails'ターミナル$ bundleapplication.js//= require rails-ujs //= require activestorage //= require turbolinks //= require jquery //= require_tree .2. booksコントローラーのcreateアクションを編集
books.controller.rbclass BooksController < ApplicationController #ローカル変数をインスタンス変数に変更 def create @book = Book.new(book_params) @book.user_id = current_user.id unless @book.save render 'index' end end end3. フォームを編集する
非同期投稿を行うときは必ず「form_with」を使用する。
※「form_for」「form_tag」だとレイアウトが崩れた。
books/index.html.erb<!-- form_withの引数に「remote: true」を追記 --> <%= form_with model: @book, remote: true do |f| %> <div class="field row"> <%= f.label :title %> <%= f.text_field :title, class: "col-xs-12 book_title" %> </div> <div class="field row"> <%= f.label :body %> <%= f.text_area :body, class: "col-xs-12 book_body" %> </div> <div class="actions row"> <%= f.submit class: "btn btn-primary col-xs-12" %> </div> <% end %>4. 投稿一覧を編集する
books/index.html.erb<tbody class="new_book"> <!-- 投稿一覧の親要素にクラスをつける --> <% @books.each do |book| %> <%= render 'books', book: book %> <!-- 投稿一覧をパーシャル化 --> <% end %> </tbody>books/_books.html.erb<tr> <td> <%= link_to book.user do %> <%= attachment_image_tag book.user, :profile_image, :fill, 50, 50, fallback: "no-image-mini.jpg" %> <% end %> </td> <td><%= link_to book.title, book %></td> <td><%= book.body %></td> </tr>5. JavaScriptファイルの作成
books/create.js.erb$(".book_title").val(''); $(".book_body").val(''); $(".new_book").prepend("<%= j(render 'books', book: @book) %>");
$(".new_book")
➡︎ 「4」で付けたクラスを指定
.prepend("<%= j(render 'books', book: @book) %>");
➡︎ 既存投稿の先頭に新規投稿を表示
$(".book_title").val('');
$(".book_body").val('');
➡︎ 入力フォームを空にする参考サイト
- 投稿日:2020-04-07T11:57:20+09:00
RailsでERBを直接使い、文字列として結果を取得する
はじめに
Railsのviewではなく、erbの結果を文字列としてほしいケースが有ったので、その方法です。
パスにRails固有のコードを使っていますが、そこ以外はRailsじゃなくても使えます。
ERBのインスタンス生成
file = File.read(Rails.root.join('app', 'views', 'hoge', 'fuga.html.erb').to_s) erb = ERB.new(file)といった形でERBのインスタンスを生成できます。
Railsじゃない場合は、
file = File.read('/path/to')みたいな感じですね。
結果の取得
result_text = erb.result_with_hash(hoge:1, fuga:2)で結果の取得ができます。
引数に渡したハッシュが、そのままerb内でkeyを変数名、valueを値とするローカル変数として読み込まれます。
あとがき
erbを直接使いたい状況、そこまで多くはないとは思いますが、もし必要な方の役に立てば幸いです。
- 投稿日:2020-04-07T11:52:04+09:00
【Rails5】rails_adminで多対多の関連付けを上手く編集する方法
はじめに
一瞬でめちゃイケてる管理画面を作ってくれる
rails_admin
今までCRUDそれぞれ画面編集してたのはなんだったんだ……と思う完成度です。しかし、多対多の関連付けの時、毎回のようにエラーが出ました。
出たエラー
ActiveRecord::HasManyThroughOrderError in RailsAdmin::Main#edit
原因
色々試しましたが、Modelでの関連付け設定の順番が原因でした。
構成
タイトルごとに複数のタグ。
タグごとに複数のタイトル。title has_many tags
tag has_many titlesこれを実現させるために、tag_mapsというテーブルを間に挟んでいます。
[tag_maps]
id
title_id
tag_id解決したコード
model/title.rbclass Title < ApplicationRecord has_many :tag_maps has_many :tags, through: :tag_maps endmodel/tag_map.rbclass TagMap < ApplicationRecord belongs_to :title belongs_to :tag endmodel/tag.rbclass Tag < ApplicationRecord has_many :tag_maps has_many :titles, through: :tag_maps endただ普通に記述してるだけなのですが、なぜか順番が逆だとエラーが出ました。
オマケの注意点
今回のこれは、Rails5での解決策でした。
(Rails 5.2.4.2)他のバージョンでは、ここ見たら参考になるかも……?
https://github.com/sferik/rails_admin/wiki/Associations-basicsあとrails_adminの編集画面で若干表示項目が変に見えるのは……まぁええでしょ。エラー出てないし
終わり
- 投稿日:2020-04-07T11:45:02+09:00
[Rails]モデル、テーブル、カラムの作成と削除コマンド
本記事について
開発して行く中で
「あれ?マイグレーションファイルの作成コマンドってこんなんだっけ。」
のように、ド忘れしてしまうことがあります。
そのため、メモ代わりに書きたいと思います。DB関係
モデル & テーブル作成
モデル & マイグレージョンファイル作成
rails g model モデル名(単数) 例 : userモデル rails g model user補足ですが上のコマンドで以下が作成されます。
1. モデルのクラスファイル
2. マイグレーションファイル
3. モデルの自動テスト
4. モデルの自動テストで使うfictureファイル実行
bundle installモデル削除
rails d model モデル名(単数)テーブルの削除
主な流れ
- マイグレーションファイル作成
- マイグレーションを編集
- 実行例: users テーブルの削除
マイグレージョンファイルの作成rails g migration DropTableUsersマイグレーションファイルの編集
2020xxxxx.rbclass DropTableUsers < ActiveRecord::Migration def change drop_table :users end end実行
bundle install既存のテーブルにカラムを追加
rails g Addカラム名Toテーブル名 カラム名:カラム型
の形でターミナルに入力しマイグレーションファイルを作成します。例: usersテーブルにstring型nameカラムを追加
rails g migration AddNameToUsers name:string実行
bundle install既存のテーブルのカラムを削除
rails g migration Removeカラム名Fromテーブル名 カラム名:テーブル名
の形でターミナルに入力しマイグレーションファイルを作成します。例: usersテーブルのstring型nameカラムを削除
rails g migration RemoveNameFromUsers name:string実行
bundle installおわり
最後まで見ていただきありがとうございました。
- 投稿日:2020-04-07T11:33:08+09:00
【Rails】マイグレーションファイルやschemaファイルの仕組み、rails db:migrate、rails db:rollbackとかを纏めてみた
マイグレーションファイルとは?
マイグレーションファイルとはデータベースの設計図のことです。
このマイグレーションファイルをどのように作成して、データベースに反映させるのか、
また、一度データベースに反映させた内容をどのように修正できるのか、自分なりに纏めてみました。マイグレーションファイルを作成し、データベースに反映させる
まずはターミナルでマイグレーションファイル(DBの設計図)を作成します。
僕の場合、text型のbodyカラムを持つ、BoardモデルとUserモデのマイグレーションファイルを作成しました。まずはreference型に
board_id:references
、user_id:references
と間違った内容を付けたとします。# 誤った内容であることに注意! rails g model comment body:text board_id:references user_id:referencesこれによって、以下のマイグレーションファイルが作成される。
db/migrate/20200330045356_create_comments.rb# 誤ったファイルであることに注意! class CreateComments < ActiveRecord::Migration[5.2] def change create_table :comments do |t| t.text :body, null: false t.references :board_id, foreign_key: true t.references :user_id, foreign_key: true t.timestamps end end endこのマイグレーションファイルを作成した段階では、データベースに反映されていません。
ターミナルで下記のrails db:migrate
コマンドを実行すると、作成したマイグレーションファイルが読み込まれ、データベースに反映されます。> rails db:migrate == 20200330045356 CreateComments: migrating =================================== -- create_table(:comments) -> 0.0143s == 20200330045356 CreateComments: migrated (0.0165s) ==========================データベースに反映されているマイグレーションファイルを確認する
そして、
rails db:migrate:status
を実行すると、DBに反映されたマイグレーションファイルを確認できます。
up
と書いているファイルがデータベースに反映されているもの(マイグレーション済みということ)です。> rails db:migrate:status Status Migration ID Migration Name -------------------------------------------------- up 20200310093526 Sorcery core up 20200316101344 Create boards up 20200316105948 Add user id to boards up 20200328064702 Add board image to board up 20200330045356 Create comments次に、スキーマファイルで現在のデータベースの構造を確認できるのですが、
下記のcommentsテーブルはboard_id_id
、user_id_id
と誤ったカラムが追加されているので、修正したいです。db/schema.rb# 誤ったテーブル内容 create_table "comments", force: :cascade do |t| t.text "body", null: false t.integer "board_id_id" t.integer "user_id_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["board_id_id"], name: "index_comments_on_board_id_id" t.index ["user_id_id"], name: "index_comments_on_user_id_id" endデータベース及びマイグレーションファイルの修正方法
まずは、
rails db:rollback
で最新のマイグレーションファイルをdown状態にします。
down状態のマイグレーションファイルは、データベースに反映されていない状態にあるということです。
(up状態にあるマイグレーションファイルを削除・編集することは避けましょう)> rails db:rollback == 20200330045356 CreateComments: reverting =================================== -- drop_table(:comments) -> 0.0044s == 20200330045356 CreateComments: reverted (0.0079s) ==========================
rails db:migrate:status
で、以下の様にdown状態になったことが確認できますね。> rails db:migrate:status Status Migration ID Migration Name -------------------------------------------------- up 20200310093526 Sorcery core up 20200316101344 Create boards up 20200316105948 Add user id to boards up 20200328064702 Add board image to board down 20200330045356 Create comments次に行う手順として、2通り方法があります。
①down状態にしたマイグレーションファイルを削除し、新しいマイグレーションファイルを作成してから、rails db:migrate
する。
②down状態にしたマイグレーションファイルを直接編集し、rails db:migrate
する。どちらでもいいのですが、今回はカラム名を修正するだけなので、②の方法を取ってみます。
board_id
をboard
に、user_id
をuser
に変更します。db/migrate/20200330045356_create_comments.rb# 誤ったファイルであることに注意! class CreateComments < ActiveRecord::Migration[5.2] def change create_table :comments do |t| t.text :body, null: false t.references :board, foreign_key: true t.references :user, foreign_key: true t.timestamps end end endこれで
rails db:migrate
すると、マイグレーションファイルがup状態に戻ります。> rails db:migrate:status Status Migration ID Migration Name -------------------------------------------------- up 20200310093526 Sorcery core up 20200316101344 Create boards up 20200316105948 Add user id to boards up 20200328064702 Add board image to board up 20200330045356 Create commentsスキーマファイルを確認すると、
db/schema.rbcreate_table "comments", force: :cascade do |t| t.text "body", null: false t.integer "board_id" t.integer "user_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["board_id"], name: "index_comments_on_board_id" t.index ["user_id"], name: "index_comments_on_user_id" end無事、正しいカラム名を持ったテーブルがデータベースに反映されました!
まとめ
最後に、ここまでの内容をまとめておきます!
- マイグレーションファイルとはデータベースの設計図のこと。
rails g model モデル名 カラム名:型
で、モデルとマイグレーションファイルを作成するrails db:migrate
で、マイグレーションファイルをDBに反映させる(up状態)rails db:rollback
で、マイグレーションファイルをDBに反映させる前の状態に戻す(down状態)rails db:migrate:status
で、各マイグレーションファイルのDBへの反映状態(up,down)を確認できる- マイグレーションファイルの修正方法は、①down状態にしたマイグレーションファイルを削除し、新しいマイグレーションファイルを作成してから、
rails db:migrate
する。もしくは、 ②down状態にしたマイグレーションファイルを直接編集し、rails db:migrate
する。
- 投稿日:2020-04-07T10:58:00+09:00
Railsチュートリアルメモ - 第14章
サマリ
- モデルの複雑な関連付けの方法
- 1つのテーブル
relationship
を使って、follower
とfollowing
を管理する方法- ネストしたルーティングの実装
- ajaxの実装
ポイント
テーブル名と異なるカラムをFKとして使用したい場合
1対多の1側
# user.rb has_many :active_relationships, class_name: "Relationship", foreign_key: "follower_id", dependent: :destroy1対多の多側
# relationship.rb # follower_idカラムが存在している必要がある belongs_to :follower, class_name: "User"
has_many
とbelongs_to
について
has_many
で指定できるパターン# モデルの複数形 e.g. microposts has_many :microposts # 別名のシンボル、クラス名、FK has_many :active_relationships, class_name: "Relationship", foreign_key: "follower_id"
- 関連付けとは別に、
has_many :hoge, through: :fuga, source: :foobar
を定義しておくと、こ配列``
belongs_to
で指定できるパターンデフォルトでは外部キーの名前を_idといったパターンとして理解し、 に当たる部分からクラス名を推測する
1. モデルのシンボル
2. 別名とクラス名class Relationship < ApplicationRecord belongs_to :follower, class_name: "User" belongs_to :followed, class_name: "User" endルーティングのカスタマイズ - ネストしたURLの設定
# /users/1/following や /users/1/followers resources :users do member do get :following, :followers end end # /users/tigers resources :users do collection do get :tigers end endAjaxの実装方法
- ローカル変数ではなくインスタンス変数への変更が必要
- viewには
form_for
の引数に, remote: true
を追加する- controllerには
respond_to
を追加するdef create @user = User.find(params[:followed_id]) current_user.follow(@user) respond_to do |format| format.html { redirect_to @user } format.js end endアンパサンド(&)を使ったブロックの短縮表記
# 以下は同値 [1, 2, 3, 4].map { |i| i.to_s } [1, 2, 3, 4].map(&:to_s)感想
- めちゃくちゃ時間がかかったがなんとか完走することができた
- チュートリアルとはいえtwitter風の動くアプリが完成したのは嬉しい
- まだまだ理解しきったといえる状態ではないので、3周目4週目をやりながら使いこなしていきたい
- 投稿日:2020-04-07T02:15:23+09:00
[Rails]JS(jquery)が動かない 初歩的ミス
jquery使用の際、同じコード引用下のに別アプリで
なぜか動かない。
と言う原因の一例です。確認した場所
■Gemfile→jqueryがインストールされているか
■application.jsにjqueryの記述があるか。
■js内にturbolinks:load
が入っているかどうか原因
コメントアウトされているコードの並び順
*これ、すごく大事でした。
初歩の初歩でテキストに書いてあった気がする。。。
//= require_tree .
が、最初はこの位置におりました。
移動!!最下部へ
こちらでjqueryが動かない問題は解決いたしました。require_tree .とは?
参考資料によると以下の記載があります(ちなみに
require_tree
はcssにも記述あります)
そしてアセットパイプライン
と言うそうです。
application内にあるcssやjsの読み込み順を司るものです。require_treeディレクティブは、指定されたディレクトリ以下の すべての JavaScriptファイルを再帰的にインクルードし、出力に含めます。 このパスは、マニフェストファイルからの相対パスとして指定する必要があります。 require_directoryディレクティブを使用すると、指定されたディレクトリの 直下にあるすべてのJavaScriptファイルのみをインクルードします。 この場合サブディレクトリを再帰的に探索しません。日本語難しい(´・ω・)
少し簡単な説明require の部分は ディレクティブ (何種類かあります)
require_directory
→与えられたディレクトリ以下のファイルを、
自身よりも前に挿入する。
順番はアルファベット順(さらに大文字→小文字)になる
require_tree
→require=directory と同じ動きをするが、再帰的に読み込む
読み込みはコードの 上から順番に 読み込まれます。上記より考えると、
require_tree
より下に書かれていたjqueryが読み込まれなかったため動かなかった(と、解釈いたしました。)[備考]
require_treeには引数として与えられたディレクトリ以下のファイルをアルファベット順に全て読み込むという意味があります。
現在require_treeの引数には.(ドット)
が渡されています。
引数.(ドット)
はカレントディレクトリを表します。
つまり、この記述によってapp/assets/javascriptsというディレクトリにあるファイルは全て読み込まれることになります。参考ページ
Rails のアセットパイプライン(Asset Pipeline)について
終わりに
こちらは、個人的解釈をもとに解決した方法を備忘録として書いております。
プログラミング初学者ゆえ、
誤記や不備、アドバイス等ございましたら御指摘いただけると幸いです。
最後まで読んでいただきありがとうございます。
- 投稿日:2020-04-07T01:03:50+09:00
【Rails】ルーティングをネストした時にshallowオプションを使うと便利だよ
ネストしたルーティングにshallowオプションを使うと便利だよ!と知ったので、自分なりに記述してみます?
ルーティングをネストする
- このような親子関係のモデルがあるとする。
- Boardモデルが
has_many :comments
- Commentモデルが
belongs_to :board
以下の記述は、ルーティングをネストすることで、掲示板(Board)とコメント(Comment)の親子関係をルーティングで表しています。
config/routes.rbresources :boards do resources :comments end次にターミナルで
rails routes
を実行し、利用可能なルーティングをすべて表示してみます。
rails routes
で確認できる情報
- ルーティング名 (あれば)
- 使用されているHTTP動詞 (そのルーティングがすべてのHTTP動詞に応答するのでない場合)
- マッチするURLパターン
- そのルーティングで使うパラメータ
# rails routes board_comments GET /boards/:board_id/comments(.:format) comments#index POST /boards/:board_id/comments(.:format) comments#create new_board_comment GET /boards/:board_id/comments/new(.:format) comments#new edit_board_comment GET /boards/:board_id/comments/:id/edit(.:format) comments#edit board_comment GET /boards/:board_id/comments/:id(.:format) comments#show PATCH /boards/:board_id/comments/:id(.:format) comments#update PUT /boards/:board_id/comments/:id(.:format) comments#update DELETE /boards/:board_id/comments/:id(.:format) comments#destroy boards GET /boards(.:format) boards#index POST /boards(.:format) boards#create new_board GET /boards/new(.:format) boards#new edit_board GET /boards/:id/edit(.:format) boards#edit board GET /boards/:id(.:format) boards#show PATCH /boards/:id(.:format) boards#update PUT /boards/:id(.:format) boards#update DELETE /boards/:id(.:format) boards#destroyこの状態だと、ある掲示板(board)のコメント(comments)の詳細ページをeditしたり、showしたりする時のURLは、
/boards/:board_id/comments/:id/edit
/boards/:board_id/comments/:id
といった風に指定する必要があり、冗長ですね。shallowオプションの登場
そこで、ネストしたルーティングに、以下の様に
shallow: true
を付けてあげます。config/routes.rbresources :boards do resources :comments, shallow: true end# rails routes board_comments GET /boards/:board_id/comments(.:format) comments#index POST /boards/:board_id/comments(.:format) comments#create new_board_comment GET /boards/:board_id/comments/new(.:format) comments#new edit_comment GET /comments/:id/edit(.:format) comments#edit comment GET /comments/:id(.:format) comments#show PATCH /comments/:id(.:format) comments#update PUT /comments/:id(.:format) comments#update DELETE /comments/:id(.:format) comments#destroy boards GET /boards(.:format) boards#index POST /boards(.:format) boards#create new_board GET /boards/new(.:format) boards#new edit_board GET /boards/:id/edit(.:format) boards#edit board GET /boards/:id(.:format) boards#show PATCH /boards/:id(.:format) boards#update PUT /boards/:id(.:format) boards#update DELETE /boards/:id(.:format) boards#destroyすると、index, new, createの3つのアクション(Commentのidを指定しないアクション)はBoardのidを必要としますが、それ以外のアクションは子のidを指定するだけで済むようになりました。
これは、
- index、new、createは、Commentのidを指定しないため、Boardのidを指定しないと、どのBoardに対するものか参照できない。
- show、edit、update、destroyは、Commentのidを指定するため、それだけで一意性を持てるから、Boardのidを指定する必要がない。
と考えると分かりやすいかなと思います!
参照先
Rails のルーティング(https://railsguides.jp/routing.html)
- 投稿日:2020-04-07T00:31:32+09:00
Perl による next_prime の実装
はじめに
アルゴリズムの勉強に、もっとプログラマ脳を鍛える数学パズル アルゴリズムが脳にしみ込む70問 を解いています。
『Q53 重さが素数の荷物を運ぶエレベーター』で素数の話が出てきました。
(Q53 は、素数+二分探索の良問です)Ruby の 素数クラス
Ruby では標準で素数を順に抽出するクラス Prime が用意されています。
ruby.rbrequire 'prime' primes = Prime.each(100).to_a # => [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]上記のコーディングで、100以下の素数の配列が生成されます。
Perl では標準モジュールが用意されていないので、Rubyに乗り換えましょう自作する必要があります。Perl による実装
primes.plmy @primes = (2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97); sub prime { my $n = shift; return $primes[$n] if defined $primes[$n]; my $newprime = $primes[-1] + 2; while ($n + 1 > @primes) { my $f = 1; for my $i (@primes) { if ($newprime % $i == 0) { $f = 0; last; } elsif ($i ** 2 > $newprime) { last; } } if ($f == 1) { $primes[@primes] = $newprime; } $newprime += 2; } $primes[$n]; } sub next_prime { my $n = shift; my $i = 0; while (1) { if ($primes[$i] == 0) { prime(scalar @primes); last if $n < $primes[$i]; } $i++; } $primes[$i]; }perl.plprint prime(80); # => 419 81番目の素数 print next_prime(743); # => 751
怠慢なので予め100以下の素数を用意しておきます。
それ以降の素数は必要に応じ、随時追加する仕様にしました。まとめ
- Ruby は prime や permutation や gcd 等が標準で用意されてます
- 今回は Perl で next_prime を実装しました
- 数学パズルはためになります