- 投稿日:2019-06-22T23:00:13+09:00
2019年にRails + Ajaxを整理してみる(サンプルアプリ&コード付き)
Rails上でAjaxを動かす、という良くありそうな話。
ただ調べてみるとやり方が色々あって、
Rails歴半年ちょいの私には何が正しいのかさっぱり分からなかった。という訳で整理してみる。同じ境遇にある人の助けになれば嬉しい。
jQueryとかを用いた、古式ゆかしい(らしい)やり方ですので、
Vue/React等をお使いの方々はおかえりください(涙)間違ってる部分とかあったら、コメントいただければ幸いです。
(特に図の部分)この記事がよく刺さりそうな人
- Railsの基礎はわかる
- Ajaxの雰囲気はわかる
- JavaScript & jQueryも本気出せばちょっと書ける
(決してチョットデキルではない)- RailsでAjaxはあまりやった事がない
もしくは「良く分からんけどまぁ動いてるからヨシ!」で乗り切ったとりあえず結論
Rails + Ajax の実現方法は、
ざっくり以下の3パターン&その組み合わせっぽい。1. Rails推奨方式
2. フロントはJavaScriptだけでやる方式
3. AjaxのリクエストはRails & レスポンス以降はJavaScriptでやる方式方式別サンプルアプリ&コード
作ったのは、フォームに文字を入力&ボタンを押すと、Ajaxを使って文字が書き換わるアプリ。
(アプリを名乗るのはおこがましいかもしれない)これを上の3方式のそれぞれでやってみた。
Ajaxでやる意味ある?というツッコミは無しで...コードは本当に必要最低限なので、色々細かいツッコミはご容赦くださいm(_ _)m
逆に手元で再現する分にはやりやすいはず。。。あとjQueryを使ってます。入れ方は以下参照。
Rails 5.2 jQuery 動かし方 - Qiita共通処理
サーバ(Rails)側の処理は、3つの方式でほぼ共通。
routes.rbRails.application.routes.draw do get 'static/top' post 'static/ajax_update', to: 'static#ajax_update' post 'static/ajax_update2', to: 'static#ajax_update2' endstatic_controller.rbclass StaticController < ApplicationController def top end # 1. Rails推奨方式 で使用 def ajax_update @text = params[:data] render end # 2. フロント側はJavaScriptだけでやる方式 # 3. AjaxのリクエストはRails & レスポンス以降はJavaScriptでやる方式 # で使用 def ajax_update2 @text = params[:data] render plain: @text end end1. Rails推奨方式
Railsガイドに書かれたやり方
Rails で JavaScript を使用する - Rails ガイドajax_update.js.erbvar user = '<%= "#{ @text }" %>' $('#ajax-test1').text(user);top.html.slimh1 Static#top p Find me in app/views/static/top.html.slim #ajax-test1 Ajax: Rails依存 #ajax-request1 = form_with url: static_ajax_update_path do |f| = f.text_field :data = f.submit 'Post Ajax'図に表すと多分以下の感じ。
もうガッツリRailsに乗っかっている状態。肝は以下2点
- xxx.js.erbからJavaScriptをレンダリングしてフロントに返す
- フロント側で受け取ったJavaScriptを実行
個人的にはRails側で、JavaScriptをレンダリングしている辺り、
少し気持ち悪い。。。ただコード量は必要最低限で済むし、
Rails推奨であることからトラブルも起きにくそう。
基本はこれでいいのではないだろうか。なお細かい処理がしたい場合には不便になることもある様子で、
何だかんだ使わないと言う話もあるらしい。
参考:https://qiita.com/ka215/items/dfa602f1ccc652cf28882. フロント側はJavaScriptだけでやる方式
Railsにあえて叛逆していくやり方。
top.html.slim#ajax-test4 Ajax: ほぼJS(jQuery) = text_field_tag 'static[ajax_data2]' = button_tag 'Post Ajax', id: 'btn2'ajax_request_response.js$(document).ready( () => { $('#btn2').on('click', (e) => { e.preventDefault(); const param = $('#static_ajax_data2').val(); // CSRFトークンを取得&セット $.ajaxPrefilter( (options, originalOptions, jqXHR) => { if (!options.crossDomain) { const token = $('meta[name="csrf-token"]').attr('content'); if (token) { return jqXHR.setRequestHeader('X-CSRF-Token', token); } } }); $.ajax({ url: `/static/ajax_update2`, type: 'POST', data: { data: param } }) .done( (data, textStatus, jqXHR) => { var result = $('#ajax-test4'); result.text(data); }); }); });図に表すと多分以下の感じ。
Ajaxに関しては、Railsには頼らないという強い意思が見える。肝は、
RailsのCSRF対策のために、
CSRFトークンの取得&セットを行なっている所。具体的なやり方は以下の記事を完全リスペクトしましたm(_ _)m
https://qiita.com/a_ishidaaa/items/7c3fa339d3bea25a9ba8ざっくり言うと、RailsではCSRFという脆弱性への対策として、
Postのリクエスト時にトークン(身分証明みたいなもの)を使っている。
ここをカバーしてあげないと、JavaScriptからPostは出来ない。そう、Railsからの叛逆に成功したと思いきや、
実はその呪縛から逃れきれていなかったのだ。
なんかエモい。なお、RailsのCSRFについての詳細は以下の記事等をご参照ください。
外部からPOSTできない?RailsのCSRF対策をまとめてみた - Qiita3. AjaxのリクエストはRails & レスポンス以降はJavaScriptでやる方式
Railsへの依存を減らしつつ、CSRF対策はRailsによろしくできるやり方。
top.html.slim= form_with url: static_ajax_update2_path, id: 'ajax-request-3' do |f| = f.text_field :data = f.submit 'Post Ajax'ajax_response.js// Ajax: form送信はRails、受信以降はJS $( () => { $('#ajax-request-3').on('ajax:success', (e) => { const result = $('#ajax-test3'); result.text(e.detail[0]); }); });図に表すと多分以下の感じ。
折衷案な雰囲気。肝は、
RailsとJavaScriptの間で、
どのようにデータをやり取りされるかの理解が必要な所。適当にやってると変なハマり方をしそう。。。
ただそこさえクリアすれば、
Railsっぽさと自由度をある程度両立できる?気がする(よく分かってない)まとめ
- 基本的には大人しく「1. Rails推奨方式」を使った方がいい気がする。
(特に経験浅めの人)- ただ不便な場合もある(らしい)ので、
その際は「3. AjaxのリクエストはRails...」を採用、
もしくは「1. Rails推奨方式」と組み合わせて使えば良さそう。- Railsで開発するけどなるべく依存したくないというワガママな人は、
「2. フロント側はJavaScriptだけでやる方式」を使えばいい...のか?参考サイト
以下本記事作成に際しお世話になったサイト。見ると理解がすごく深まる。。。
Ruby on RailsのAjax処理のおさらい - Qiita
Rails 5.1+jQueryでajaxを試す (罠にハマる) - Qiita
Rails 5.2 jQuery 動かし方 - Qiita
RailsでのAjax - Qiita
jQuery.ajax()のまとめ: 小粋空間
Rails 5.2 jQuery 動かし方 - Qiita
- 投稿日:2019-06-22T22:24:48+09:00
railsで複数ワードでの検索機能(end)とマイナス検索機能(-)を実装してみる
はじめに
半年前にrailsで複数ワードでの検索機能(or)とマイナス検索機能(-)を実装してみるという記事を投稿させてもらったのですが、沢山の方に見てもらい良質なフィードバックまで頂きました。本当にありがとうございます!
そこで記事の続きという訳では無いですが、複数ワードでの検索時にorでは無くendで検索ができるようなコードをフィードバックを踏まえて書いてみました。また今回も完成品のコードを最後に置いておきます。環境
Ruby 2.3.3
Rails 5.2.3
MySQL 8.0.13前提として
まず前提としてこんな感じの検索フォームからコントローラの方に検索ワードを送る。
index.html.erb<%= form_tag('/items/search', method: :get) do %> <input id="page_name" name='keyword' size="30" type="text" /> <% end %>その後にコントローラで入力された検索ワードに合わせてデータを引っ張ってきて表示する。
search.html.erb<% @items.each do |item| %> <%= item.name %> <% end %>ちなみにDBにはこんなデータが入っているとします。
mysql> select name from items; +------------------+ | name | +------------------+ | 水筒A | | 水筒B | | 水筒C | | 大きい水筒 | | 大きい水筒A | | 小さい水筒 | | 小さい水筒A | +------------------+ 7 rows in set (0.00 sec)前提のコード(orとマイナス検索)
# キーワード分割 keywords = params[:keyword].split(/[[:blank:]]+/).select(&:present?) # 普通のキーワードとマイナスのキーワードを分ける negative_keywords, positive_keywords = keywords.partition {|keyword| keyword.start_with?("-") } # 空のモデルオブジェクト作成(何も入っていない空配列のようなもの) @items = Item.none # 検索ワードの数だけor検索を行う positive_keywords.each do |keyword| @items = @items.or(Item.where("name LIKE ?", "%#{keyword}%")) end # -(マイナス)がついた検索ワードの数だけnot検索を行う negative_keywords.each do |keyword| @items.where!("name NOT LIKE ?", "%#{keyword.delete_prefix('-')}%") end前回の記事でkg8mさんから教えて頂いた複数ワードでの検索機能(or)とマイナス検索機能(-)のコードです。短くて素敵。これをorからandに変えていく形で解説を入れながらコードを書いていきます。
実際に書いてみる
必要な作業は
1,送られてきたキーワードを空白で区切る(キーワード分割)
2,普通のキーワードと-(マイナス)のついたキーワードを分ける
3,普通のキーワード群でAND検索を行う
4,-(マイナス)のキーワードでNOT検索を行う早速1から行きます。
1、送られてきたキーワードを空白で区切る(キーワード分割)
検索フォームから送られてきた「水筒 A -小さい」のようなキーワードの文字列を「"水筒","A","-小さい"」と空白で区切って複数のワードに分ける作業です。この時はまだマイナスは気にしません。
items_controller.rbdef search # キーワード分割 keywords = params[:keyword].split(/[[:blank:]]+/).select(&:present?) endparams[:keyword]に検索フォームで入力された検索ワードが入っています。
それをsplitメソッドで分割を行います。[:blank:]は簡単に言ったら空白やタブという意味です(この記事を参考にしました)。つまり空白で区切って配列にするぜ!という意味になります。その後にselectメソッドで配列から何も入っていない要素を削除します。このメソッドの使い方はリファレンスを見るとわかりやすい。あ、present?はちょっと説明が難しいのですが何か値があるか?で真と偽を返すようです。
そもそも空白で区切ってなんで配列の要素にそんなのがあんだよ!ってなるんですが、前回の記事のここに理由を書いてあるので気になった方は読んでみてください。2、普通のキーワードと-(マイナス)のついたキーワードを分ける
「"水筒","A","-小さい"」のように配列になったキーワード群を普通のキーワードの配列とマイナスのキーワードの配列に分けます。
items_controller.rbdef search # キーワード分割 keywords = params[:keyword].split(/[[:blank:]]+/).select(&:present?) # 普通のキーワードとマイナスのキーワードを分ける negative_keywords, positive_keywords = keywords.partition {|keyword| keyword.start_with?("-") } end
keywords
に配列で検索ワードが入っています。これをpartitionメソッドで普通の検索ワードが入った配列とマイナスの検索ワードが入った配列に分けます。
partitionメソッドは配列の要素1つ1つを調べて真になったら1つめの配列型の変数に(今回の場合はnegative_keywords)、偽だったら2つめの配列型の変数に(今回の場合はpositive_keywords)に入れ直してくれます。
今回は1つ1つのキーワードに対してstart_with?("-")としているので要素の先頭が「-」だったらnegative_keywordsに要素を入れるといった動きになります。3,普通のキーワード群でAND検索を行う
ここが一番大切なポイントです!この部分はor検索の時は以下のようになっていました。
items_controller.rb# 検索ワードの数だけor検索を行う positive_keywords.each do |keyword| @items = @items.or(Item.where("name LIKE ?", "%#{keyword}%")) endキーワードを1つづつwhereで検索をかけてそれをorで繋げる感じ。ただ今回はandなので普通にwhere句を重ねていく。
items_controller.rbdef search # キーワード分割 keywords = params[:keyword].split(/[[:blank:]]+/).select(&:present?) # 普通のキーワードとマイナスのキーワードを分ける negative_keywords, positive_keywords = keywords.partition {|keyword| keyword.start_with?("-") } # Itemモデルオブジェクト作成 @items = Item # 検索ワードの数だけand検索を行う positive_keywords.each do |keyword| @items = @items.where("name LIKE ?", "%#{keyword}%") end endこれでいけるはず。
ただし@items = Item
はどうなんでしょうかね?これOKなんですかね?4,-(マイナス)のキーワードでNOT検索を行う
ここは元の所と変える必要が無かった。はずだった。
とりあえず元のコードを解説。items_controller.rb# -(マイナス)がついた検索ワードの数だけnot検索を行う negative_keywords.each do |keyword| @items.where!("name NOT LIKE ?", "%#{keyword.delete_prefix('-')}%") endNOT LIKEでキーワードに引っかかったデータを除外している。delete_prefixメソッドは文字列の先頭に引数の文字があれば削除するというもの。negative_keywordsにはマイナスキーワードが ["-小さい","-コンパクト"] といった感じで入っていますが、これをこのまま「-小さい」で検索しても「小さい」にはヒットしません。
なのでdelete_prefixを使い先頭の-を削除してから検索をしている訳です。で、問題はここから。このdelete_prefixメソッドはRubyのバージョンが2.5で実装されたメソッドなので自分の開発環境の2.3では使えない。このメソッドを教えて頂いた前回の記事ではあろうことか開発環境の項目にrailsとMysqlだけでRubyのバージョンを書いていないというアホみたいな事をやらかしているという・・・すまねぇすまねぇ。
しょうがないのでdelete_prefixを使わない方向で実装する。
items_controller.rbdef search # キーワード分割 keywords = params[:keyword].split(/[[:blank:]]+/).select(&:present?) # 普通のキーワードとマイナスのキーワードを分ける negative_keywords, positive_keywords = keywords.partition {|keyword| keyword.start_with?("-") } # Itemモデルオブジェクト作成 @items = Item # 検索ワードの数だけand検索を行う positive_keywords.each do |keyword| @items = @items.where("name LIKE ?", "%#{keyword}%") end # マイナスキーワードの先頭から-を取り除く negative_keywords.each {|word| word.slice!(/^-/) } # マイナスキーワードでnot検索 negative_keywords.each do |keyword| next if keyword.blank? @items = @items.where.not("name LIKE ?", "%#{keyword}%") end endまずslice!メソッドでマイナスキーワードから先頭の-を取り除く。そして後はnot検索を行います。keyword.blank?は「""」みたいな要素が来た時の対策です。詳しくは前回の記事のここを見てみてください。
これで完成です!
改善点
@items = Item
がちょっと気になる。
元々のor検索では@items = Item.none
だったけど、and検索だと常に検索結果が0件になる。推測だけどnoneは空のモデルを取得するって意味らしいが、アクションレコードとしてSQLが発行されて何もヒットしなかった(だから空のモデル)扱いになってるのかな?
だとすると「"水筒","大きい"」で検索した場合条件は
1.none(ヒット無し)
2.水筒
3.大きい
になるから、orだったら1~3のどれかに合致すればデータを引っ張ってこれたけど、andだと全ての条件に合致しなければいけないから何のデータにも引っかからないnoneがあると検索結果が常に0件になるんだと思う。なので@items = Item.all
で取り敢えず全データを入れてたけれど、all無しでも動いたので無しで動かしてる。アクションレコードに関しては勉強不足だなー。完成品(コード)
items_controller.rbdef search keywords = params[:keyword].split(/[[:blank:]]+/).select(&:present?) negative_keywords, positive_keywords = keywords.partition {|keyword| keyword.start_with?("-") } @items = Item positive_keywords.each do |keyword| @items = @items.where("name LIKE ?", "%#{keyword}%") end negative_keywords.each {|word| word.slice!(/^-/) } negative_keywords.each do |keyword| next if keyword.blank? @items = @items.where.not("name LIKE ?", "%#{keyword}%") end endあと今回のコードは検索フォームにキーワードが入力されていなかった場合の処理を書いていないので必要に応じて付け足してください。
おわりに
Ruby(Rails)は面白いメソッドが多いと思う。自分でガリガリ書かなくても良いようになっていて便利だと感じています。あと久しぶりに記事を書いたからマトモに書けてるか心配です・・・
- 投稿日:2019-06-22T21:51:24+09:00
Qiitaを始めてみました。
初めまして、ユウキと言います。
今35歳の労働ワーカーですが、以前から興味があったプログラミング学習を
2019年から始めました最初はHTMLとCSSの学習をドットインストールやprogateなどを使って行い、
サンプルサイトを作ったりしていました。そして今週からRUbyの勉強を開始。まだ条件分岐などの基礎な部分しかしてないですが、
とても楽しいです近い将来、WEBサービスの開発やプログラマーとしてお仕事したいんですが、今は毎日コツコツ
手を動かし、思考してステップアップに励んでいます。身近にプログラマーや学習している方々がいないので、こちらのサイトでは色々な方々と交流できれば
幸いです!どうぞよろしくお願いします。
- 投稿日:2019-06-22T19:22:12+09:00
現場で使うコントローラーの作成方法
概要
プログラミングスクールなどで習う
rails g controller コントローラー名
というコマンドでのコントローラー作成方法は、実際の現場では使用する頻度が少ないという。では実際の現場で使うコントローラー作成方法をどのようなものなのか。簡単にまとめてみた。なぜ現場では
rails g controller コントローラー名
というコマンドで作成しないのか?結論!!余計なファイルができると管理しづらい!
これに尽きるということ!
では実際はどうやるのか…
現場で使うコントローラー作成方法とは
1.app/controllers/の中に新しいファイルを作成。
app/controllers/ディレクトリの中に
コントローラー名_controller.rb
という新しいファイルを作成する。2.
コントローラー名_controller.rb
に、コントローラークラスを作成していく。class コントローラー名Controller endこれだけだと、クラスを定義しただけなので、コントローラーとして機能しない。
なので、app/controllers/application_controllerの機能を引き継いであげる。(
< ApplicationController
を追加)class コントローラー名Controller < ApplicationController endこれで、コントローラー名Controllerが、コントローラーとしての役割をしてくれるため、
結果 → コントローラー作成!!(ApplicationControllerの機能をすべて引き継いだ)
まとめ
以上、現場で使うコントローラー作成方法をまとめてみた。今回は実際に現場で働いた実績のあるフリーランスエンジニアの方の方法を自分なりに噛み砕いて、アウトプット。初学者ないし、これからエンジニアとして現場に入る方の参考になれば幸いです。
- 投稿日:2019-06-22T18:49:42+09:00
【初学者向け】プログラミングで処理を実装する時は流れを考えよう!
はじめに
初学者向けに書いています。
一連の処理を作るときの考え方を書きました。意識して欲しいこと
実装の要素を分解し、流れを考える
何かを実装したいと思ったら、その実装に必要な要素やフロー(流れ)を考えて書き出してみましょう。
料理で例えましょう。
あなたは「カレーを作りたい」と思った時、魔法使いでも無い限りいきなりカレーを空間に出現することはできないと思います。
きっと手順として頭の中で以下と似た様なフローを思い描くと思います。
(※食材の調達や細かい工程は割愛しています。カレールゥじゃ無くてスパイスからとかレトルトをチンするとか言わない。)
- 具材を切る
- 具材を炒める
- カレールゥを入れて煮込む
プログラミングも同じです。
何かを実装したいと思ったら上記の様にフローを思い描いてから実装に取り組んでみましょう。
そうすればどんな処理が必要か、何の値が必要かと行ったことが明確になり、実装中に迷子にならずに済みます。具体例
あなたは唐突に「ユーザーに入力させた数字を二乗にして表示したい」という気持ちに駆られたとします。
この処理をフローで書き出しましょう。大体以下の様になるかと思います。
- ユーザーに数字を入力させる
- 数字を二乗する
- 答えを表示する
というわけで早速実装しましょう。
慣れるまでは作業ファイルにコメントアウトでフローを書いておくのもありですね。作業ファイル# 好きな数字を入力させる # 二乗する # 表示する丁寧に描くとこんな感じ。
作業ファイル# 好きな数字を入力させる input = gets.to_i # 二乗する answer = input ** 2 # 表示する puts "二乗した結果#{answer}になりました。"もちろんプログラミングは自由に書いて良いので上記が絶対では無いです。
3行も書くのは勿体無いなというストイックマンは1行で実装するかもしれないしストイックマンputs "二乗した結果#{gets.to_i ** 2}になりました。"丁寧な人は、入力させる前にユーザーに分かりやすいようアナウンスを入れて、尚且つ二乗処理を使い回せる様にメソッドにするかもしれません。
丁寧な人def multi(number) number ** 2 end puts "好きな数字を入力してください。" puts "二乗した結果#{multi(gets.to_i)}になりました。"どの様に書いても結果良ければ全てよし!ではありますが、ゆくゆくは他人と一緒に開発することを想定して読みやすく、無駄なく書く様心がけましょう。
まとめ
今回の具体例はフローを書くまでもなくとても簡単な処理ですが、複雑な処理になると初学者は何を書いているか見失いがちです。
実装したいことに向けてしっかりと必要な要素、フローを書いて落ち着いてして一つ一つ実装して行きましょう。最後に
「ここが分かりにくかった」「これは何?」などの質問や、レイアウト等の書き方にアドバイスがある方はお気軽に(優しく)コメントを頂けると助かります。
- 投稿日:2019-06-22T16:42:52+09:00
rails g ~ で指定のディレクトリ下にフォルダを格納したい場合
超基本ですが、一応メモってことで書いときます。
apiモードで作成する時、app/controllers/api/v1の下にuserコントローラーを置きたい時は、
terminal$ rails g controller api::v1::users index show new create edit update destroyこれで、
app/controllers/api/v1/user_controller.rb # これが作成されるルーティングは、こうですね。
config/routes.rbnamespace 'api' do namespace 'v1' do resources :users end end
- 投稿日:2019-06-22T16:42:52+09:00
rails g ~ でapp/controllers/api/v1みたいな感じでファイルを格納したい場合
超基本ですが、一応メモってことで書いときます。
apiモードで作成する時、app/controllers/api/v1の下にuserコントローラーを置きたい時は、
terminal$ rails g controller api::v1::users index show new create edit update destroyこれで、
app/controllers/api/v1/user_controller.rb # これが作成されるルーティングは、こうですね。
config/routes.rbnamespace 'api' do namespace 'v1' do resources :users end end
- 投稿日:2019-06-22T15:25:55+09:00
RubyのバージョンアップをしたらHerokuにデプロイできなくなった
tl;dr
個人でつくってるプロダクトで
ふと思い立って、Rubyのバージョンアップを行ったら
Herokuにデプロイできなくなった
それの解決方法というか、、
原因
Rubyのバージョンアップの際に、
gem install bundler
をして
Bundlerのバージョンが2.0.2
となったからっぽい$ bundle -v Bundler version 2.0.2Gemfile.lockBUNDLED WITH 2.0.2Bundlerを
2.0.1
で入れ直して、Gemfile.lock
もつくりなおす$ gem uninstall bundler$ gem install bundler -v 2.0.1 $ bundle -v Bundler version 2.0.1$ rm Gemfile.lock $ bundle --without productionこれでできる
$ git push heroku masterおまけ
バージョンアップしたらRailsコマンドが叩けなくなった
rbenv: rails: command not found The `rails' command exists in these Ruby versions:$ rbenv exec gem install bundler $ rbenv rehash $ gem install rails
- 投稿日:2019-06-22T11:57:11+09:00
【Mac】まだ初期のrubyバージョン使用しているの?rbenvを使ってバージョンをコントロールしよう!
想定読者
- 初期のRubyのバージョンを使用している人
- rbenvを知らない人
- 最新のRubyを触りたい人。
得られるもの
- 最新のRubyを使うことができる。(今回はRuby2.6.3を使用。)
- バージョンコントロールの方法がなんとなくわかる。
準備するもの
- Homebrew
- 学ぶ気持ち
筆者のPCスペック
-macOS Mojave 10.14.5
rbenvって何?
簡単に言うとRubyのバージョンを簡単に変えることができるツールです。
ただし、バージョンを変えるだけで実際にはRubyをインストールはしません。
Rubyもインストールする際はruby-buildもインストールする必要があります。初めに
最初にHomebrewがインストールされているか確認しましょう。
Homebrewの確認は下記のコマンドです。$ brew -v Homebrew 2.1.3 Homebrew/homebrew-core (git revision 66a23; last commit 2019-05-22)※$マークはコピーしなくていいです。
上記が出なかったらこちらからインストールしましょう。手順
rbenvとruby-buildのインストール
下記のコマンドを打ちましょう。
$ brew install rbenv ruby-build実際に入っているか確認しましょう、
$ brew list autoconf openssl pkg-config rbenv ruby-build $ rbenv -v rbenv 1.1.2 $ ruby-build --version ruby-build 20190423先ほどインストールした以外にも
autoconf
やopenssl
、pkg-config
等入っていますが、今は気にしないでください。実際にインストールはできているので、次はrbenvの実行後を反映させる為の準備を行なっていきます。
rbenvを初期設定する。
現在rbenvでrubyをインストールしても実行結果は反映されません。
シェルにrubyはrbenvでインストールされたものを使う事を読み込ませる必要があります。下記のコマンドを打って初期設定を済ませてください。
$ rbenv init # Load rbenv automatically by appending # the following to ~/.bash_profile: eval "$(rbenv init -)" $ echo eval "$(rbenv init -)" > ~/.bash_profile $ source ~/.bash_profileこちらで準備ができました。
次にバージョンの選択を行いましょう。バージョンを選択する。
下記のコマンドを打つと、rbenvが持っているRubyのバージョンを全て表示してくれます。
$ rbenv install -l Available versions: -----一部抜粋----- 2.6.2 2.6.3 2.7.0-dev 2.7.0-preview1 -----一部抜粋-----今回は2.6.3を選択します。(2.7.0はありますが、安定版ではないので今回はインストールを行いません。)
選択すると、ruby-buildが自動的に起動し、インストールを行ってくれます。$ rbenv install 2.6.3 ruby-build: use openssl from homebrew Downloading ruby-2.6.3.tar.bz2... -> https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.3.tar.bz2 Installing ruby-2.6.3... Installed ruby-2.6.3 to /Users/username/.rbenv/versions/2.6.3選択したバージョンを使用する
下記のコマンドでどのrubyをインストールしたか確認できます。
*が今使っているバージョンです。systemというのは初期のバージョンを使用していることを指します。$ rbenv versions * system (set by /Users/username/.rbenv/version) 2.6.3今回は新しくインストールした"2.6.3"を使用してみましょう。
$ rbenv global 2.6.3 $ rbenv version system * 2.6.3 (set by /Users/username/.rbenv/version)実際にバージョンを確認してみましょう。
$ ruby -v ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin18]これで無事にインストールできました!
違うバージョンを使用する際は再度バージョンを選択→インストール→選択する
を繰り返す事でバージョンを自由に変更することができます。
- 投稿日:2019-06-22T10:46:41+09:00
Rails で名前付きルーティングと通常ルーティングを併用したいとき
はじめに
Rails の URL で、通常の
/hoge/:id
のようなルーティングと/hoge/fuga
のような名前付きルーティングを併用したいという課題がありました。その際どのように対応したのかを備忘として残しておきます。
前提環境
- Rails 5.2.2.1
サンプル例
name
カラムのあるPost
モデルを例にします。このモデルの
name
カラムに文字列が入っていれば、id
ではなくname
の文字列を URL として使うことを想定します。
name
が空 →/posts/1
name
にhoge
と入っている →/posts/hoge
方針
方針としては、Rails ガイド を参考に、以下のように進めました。
- routes で利用するパラメータ識別子修正
- ActiveRecord::Base#to_param をオーバーライド
- 名前付きルーティング・通常ルーティングどちらでもレコードを find できるメソッド作成
対応
routes で利用するパラメータ識別子修正
まず、routes のパラメータ識別子を修正します。
param
オプションを使うことで可能です。
id
かname
で find したかったので、id_or_name
というパラメータ名にしています。Rails.application.routes.draw do # 中略 resources :posts, param: :id_or_name # 中略 endActiveRecord::Base#to_param をオーバーライド
次に、
ActiveRecord::Base#to_param
をオーバーライドします。
name
があればname
を、存在しなければそのままid
を利用する形としました。class Post < ApplicationRecord # 中略 def to_param return name if name.presence super end end名前付きルーティング・通常ルーティングどちらでもレコードを find できるメソッド作成
最後に、
Post
モデルに名前付きルーティング・通常ルーティングどちらでもレコードを find できるメソッドを追加します。
id
かname
でレコードを検索し、どちらかがマッチしていればそのレコードを返却します。
存在しない場合は一応ActiveRecord::RecordNotFound
で例外処理しています。class Post < ApplicationRecord # 中略 def self.find_by_id_or_name(id_or_name) if object = self.where(id: id_or_name).or(self.where(slug: id_or_name)).first object else raise ActiveRecord::RecordNotFound end end end利用するときは以下のようなメソッドの呼び出し方となります。
Post.find_by_id_or_name(params[:id_or_name])終わりに
name
重複する場合など、考慮する点はまだあるかも知れませんが、一旦こちらで対応はできました。もっと良いやり方などありましたらコメントいただけるとありがたいです!
参考
- 投稿日:2019-06-22T10:46:05+09:00
Rails ~会員登録~
これまでのあらすじ
- 仮登録でメールアドレスを登録
- 登録したメールアドレスへ本登録画面に飛ぶURLを記載したメールを送信
- メールでURLへ遷移
- 登録に必要な情報の入力
- 登録完了
- ログイン
- ログアウト
までやっていきたいと思います。
メール送信
前の記事でユーザ仮登録のモーダルウィンドウ表示まで実装しました。
で、登録ボタンで以下のアクションを呼びます。top_controller.rbdef create @temp_user = TempUser.create_temp_user(temp_users_params) respond_to do |format| if @temp_user.save UserMailer.with(temp_user: @temp_user, locale: params[:locale]).request_registration.deliver_later format.js { @status = "success" } else format.js { @status = "fail" } end end endTempUserクラスの#create_temp_userメソッドで初期化します。
temp_user.rb# 仮ユーザの作成 def create_temp_user(params) # temp_usersにmail_addressで検索 初期化する temp_user = find_or_initialize_by(mail_address: params[:mail_address]) temp_user.last_name = params[:last_name] temp_user.first_name = params[:first_name] temp_user.token = create_token temp_user.expired_at = DateTime.now + 1 return temp_user endfind_or_initialize_byでメールアドレスを検索します。
もし、仮登録済みで本登録していないメールアドレスの場合、後勝ちにして最後に入力した情報でUPDATEします。
もし、temp_userにない場合は、入力情報でINSERTします。
find_or_initialize_byを使用し、saveをするタイミングでINSERTかUPDATEか判定、UPSERTが実現できます。expired_at(有効期限)は、とりあえず1日にしていますが、設定を外出ししたいですね。
saveメソッドの戻り値でSQLの成功・失敗を判定して処理を判定しています。
成功時は、登録情報を元にUserMailerでメールを作成しています。
user_mailer.rbclass UserMailer < ApplicationMailer default from: "hogehoge@gmail.com" def request_registration @temp_user = params[:temp_user] @locale = params[:locale] mail(to: @temp_user.mail_address, subject: I18n.t("mailers.user_mailer.request_registration.subject")) end endApplicationMailerを継承したUserMailerです。
from:は送信元のメールアドレスを設定します。
request_registrationがメール送信の本体です。
paramsで引数を受け取ってメールを生成します。メール本体は、viewsの下に作ります。
request_registration.html.erb<%= stylesheet_link_tag "mailers/request_registration.css", media: "all" %> <p class="message"><%= t('mailers.user_mailer.request_registration.dear', last_name: @temp_user.last_name, first_name: @temp_user.first_name) %></p> <pre class="message"><%= t('mailers.user_mailer.request_registration.message_text', expired_at: l(@temp_user.expired_at, format: :default)) %></pre> <div class="btn"> <%= link_to t('mailers.user_mailer.request_registration.button'), {controller: 'account', action: 'regist', locale: @locale, token: @temp_user.token } %> </div>メソッド名のhtml.erb(HTMLメール)またはtext.erb(テキストメール)を雛形として作ります。
上記は、HTMLメールの雛形です。link_toでaccount_controller.rbのregistメソッドを指定しています。temp_user登録の際、生成したtokenをGETリクエストをパラメタとしてURLに付与し、link_toで生成しています。
メールを受信する
開発中に動作確認したいですが、実際に送ると、誤送信する恐れがあるので、以下のgemを入れます。
Gemfile# letter_opener_web gem 'letter_opener_web', '~> 1.0'このgemはメールを送信・受信してくれます。
config/environments/development.rbに設定を追加します。development.rbconfig.action_mailer.delivery_method = :letter_opener_webまた、routes.rbに以下のパスを設定し、送信メールを確認できるようにします。
routes.rb# letter_opener_web mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.development?これで(http://localhost:3000/letter_opener) でアプリが送信したメールをブラウザで確認できます。
登録
メールに記載されたURLを押下すると、登録に必要な情報を入力する画面へ遷移できます。
パスワードについて
ライブラリを使わないでログイン機能を実装するために以下のgemを使います。
Gemfile# Use ActiveModel has_secure_password gem 'bcrypt', '~> 3.1.7'Userモデルにhas_secure_passwordを追加します。
user.rbclass User < ApplicationRecord include ActiveModel::Validations has_secure_password validations: true validates :last_name, presence: true validates :first_name, presence: true validates :last_name_roman, upper_case_format: true, unless: Proc.new { |p| p.last_name_roman.blank? } validates :first_name_roman, upper_case_format: true, unless: Proc.new { |p| p.first_name_roman.blank? } validates :sex, inclusion: { in: [0, 1] } validates :birthed_on, presence: true validates :mail_address, uniqueness: true validates :password, password_format: true validate :already_used_mail_address # already used mail address def already_used_mail_address unless User.find_by(mail_address: mail_address).nil? errors.add(:mail_address, I18n.t("validate.already_use")) end end # create remember token def self.create_remember_token SecureRandom.urlsafe_base64 end # encrypt def self.encrypt(token) Digest::SHA256.hexdigest(token.to_s) end endpasswordとpassword_confirmation属性、さらにauthenticateメソッドが使用できるようになります。
さらにDB内ではpassword_digestというカラムで暗号化されたパスワードは保存されます。
(password_digestをmigrationで対象のテーブルに追加します。)アプリケーションログには、入力値は当然出力されず
DBには、暗号化されたパスワード文字列が登録されます。登録ボタンでcreateメソッドが呼び出され、登録成功したら完了画面、失敗したら再度登録画面をレンダリングします。
account_controller.rbdef create @user = User.new(users_params) if @user.save render action: :complete else render action: :regist end end
ログイン・ログアウト
application_controller.rbに以下を定義します。
application_controller.rbclass ApplicationController < ActionController::Base # filter # actionの直前に実行されるfilter before_action :set_locale before_action :current_user before_action :require_sign_in! # helper methodとして使用できる helper_method :signed_in? def set_locale I18n.locale = locale end def locale @locale ||= params[:locale] ||= I18n.default_locale end def default_url_options(options = {}) options.merge(locale: locale) end def current_user remember_token = User.encrypt(cookies[:remember_token]) @current_user ||= User.find_by(remember_token: remember_token) end def sign_in(user) remember_token = User.create_remember_token # cookieにremember_tokenをsetする cookies.permanent[:remember_token] = remember_token # remember_tokenを更新する user.update_column(:remember_token, User.encrypt(remember_token)) @current_user = user end def sign_out @current_user = nil # cookieのremember_tokenを削除する cookies.delete(:remember_token) redirect_to login_path end def signed_in? @current_user.present? end private def require_sign_in! redirect_to login_path unless signed_in? end endfilter処理として
current_userメソッド
ログイン時にCookieとDBに登録したトークン情報を突き合わせて、ユーザ情報を取得する
require_sign_in!メソッド
ユーザ情報が取得できない場合(=ログインしていない場合)ログイン画面へリダイレクトするこれをapplication_controller.rbに定義することによりapplication_controllerを継承する全てのcontrollerにこのfilter処理が走ります。
これにより画面上でログイン状態・非ログイン状態を判断するわけです。
ログイン処理はsession_controller.rbに定義しています。
session_controller.rbclass SessionsController < ApplicationController # filter # actionの直前に実行されるfilterをskipする skip_before_action :require_sign_in!, only: [:new, :create] # actionの直前に実行されるfilter before_action :set_user, only: [:create] # GET /login def new redirect_to root_path end # PUT /login def create if @user.authenticate(@session.password) sign_in(@user) else @session.sign_in_failure end render "top/index" end # DELETE /logout def destroy sign_out redirect_to login_path end private def set_user @session = Session.new(session_params) if !@session.valid? render "top/index" and return end @user = User.find_by!(mail_address: @session.mail_address) rescue @session.sign_in_failure render "top/index" end def session_params params.require(:session).permit(:mail_address, :password) end endSessionモデルはmail_addressとpasswordのログイン認証に必要な情報をもっているクラスです。
skip_before_actionは、actionの直前に実行されるfilterをskipするための宣言です。
当然ログイン画面表示とログイン処理にログイン認証のfilterが入っているとログインできないため、skipしています。createメソッドの前のみset_userのfilterが適用されます。
set_userメソッドは画面から入力されたフォーム情報を元にmail_addressでユーザ情報を取得します。
取得できない場合、例外を発生させます。例外発生時はログイン画面をレンダリングします。createメソッドは、set_userメソッドで取得したユーザ情報とパスワードを確認します。
確認できた場合、ログイン処理(application_controller.rbに定義)をします。ログイン処理は、ログイン認証していることを示す、remember_tokenを画面に保持します。
remember_tokenはUserクラスで定義したメソッドでランダム文字列で生成されます。
それをCookieに保存し、その後DB(userテーブル)UPDATEします。前述のログイン確認のfilterはこのremember_tokenを元にログインしているか、していないかを判断するというわけです。
終わりに
- 勉強会の資料なので、急いで作ったので、もうちょっと修正します。
- 参考リンクとかも記載せねば…
参考
工事中…
- 投稿日:2019-06-22T03:22:19+09:00
「プログラミング言語の歴史を会話方式で振り返る」を横目で見ながらの会話
この記事は,以下の記事を見ながら書いた。
プログラミング言語の歴史を会話方式で振り返る - Qiita
いろいろな言語が挙げられているが,「あの言語も書けばいいのに」というのは誰でもたくさん思いつくだろう。しかし,それを言い出すとキリが無いので別記事にした。
作風およびキャラクターは @Yametaro さんによる一連の記事を直接真似ている(許してや〜)。
登場人物は以下のとおり
- やめ太郎:最近どっかの会社に転職したおじさんプログラマー。
- ルビ子:やめ太郎が勤める会社の社長の娘。物マニア(決して monomania=偏執狂 ではない)というかオブジェ嗜好な女子。
なお,筆者はこの記事に出てくる三つの言語はどれも知らん。ツッコミ歓迎やで。
プロローグ
やめ太郎「つまりこの記事はパクリ言うことやな」
筆者「パクリとは人聞きが悪いな,オマージュやがな」
ルビ子「うち,めっちゃ好き! 最中も人形焼も!」
やめ太郎「それはおまんじゅうや!」やめ太郎「ぼちぼち始めよか」
ルビ子「うち,C# と同い年や」
やめ太郎「えっ,シーシャ?」
ルビ子「水タバコとちゃうわ!」SNOBOL
ルビ子「ちょっとマイナーなとこで SNOBOL とか」
やめ太郎「ワイ南国生まれやらウインタースポーツはちょっとなあ」
ルビ子「スノーボードちゃうわっ! SNOBOL やっ!」
やめ太郎「登場が 1962 年か,古いな」
ルビ子「うち,生まれてへんし」やめ太郎「なんで SNOBOL なん?」
ルビ子「連想配列ってあるやん」
やめ太郎「Ruby ではハシシいうんやろ?」
ルビ子「大麻吸ってどないすんねん! ハッシュやっ!」
やめ太郎「せやなー」
ルビ子「あれのルーツが SNOBOL らしいねん」
やめ太郎「ほな,今のほとんどの言語に影響しとるやん」
ルビ子「そやねん」
やめ太郎「すごいな」
ルビ子「組込みで連想配列を持ったんは SNOBOL4 が最初らしいわ」
やめ太郎「へー」Occam
ルビ子「次,Occam いこか」
やめ太郎「知らんからほっかむりするで」
ルビ子「スルーしたるわ」
やめ太郎「で,なんで Occam なん?」ルビ子「Occam はトランスピューターっていう並列コンピューティング用のマイクロプロセッサーのために開発された言語やねんて」
やめ太郎「え? ルビ子ちゃん,ぴゅう太 知っとるんか,懐かしいなあ」
ルビ子「そうそう,日本語 BASIC でモシ 〜 ナラバ
……ってちゃうわっ!」
やめ太郎「まあどっちも 1980 年代前半に登場したんやけどな」
ルビ子「分かっとってボケたんかい!」
やめ太郎「てゆーか,ホンマにぴゅう太を知っとったとは」
ルビ子「Wikipedia で見ただけやで〜」やめ太郎「そういえばワイの知り合いでもトランスピューターで数値計算しとったんがおったような」
ルビ子「今の GPU だのマルチコアだのよりも遥か昔によお」
やめ太郎「スゴイな」ルビ子「Occam は実用的な並列計算機用言語として先駆的やったんやね」
やめ太郎「言語の特徴とかは?」
ルビ子「Wikipedia からのコピペやけど,直列に計算してほしいところはこう」SEQ x := x + 1 y := x * xルビ子「並列に計算してほしいところはこう」
PAR x := x + 1 y := y * 2やめ太郎「インデントが気になるな」
ルビ子「そう,Occam は階層構造をインデントで表すわけ」
やめ太郎「分かった! そういうのを,アレ,ええと,ユーミンの曲で『何をゴールにするねん』みたいな」
ルビ子「それは『ノーサイド』やろ! インデントで階層を表すんはオフサイドルールや!」
やめ太郎「オフサイドルールと言えばバイソンやな」
ルビ子「Python や!」
やめ太郎「掃除機ちゃうんか」
ルビ子「それは Dyson やっちゅーねん!」
やめ太郎「その Python のイメージが強いから 1990 年代かと思った」
ルビ子「オフサイドルール自体は 1960 年代からあるらしいで」
やめ太郎「へー」CLU
やめ太郎「CLU って登場が 1974 年か,聞いたこともないわ」
ルビ子「あんまり使われへんかったみたいね」
やめ太郎「誰が考えたん?」
ルビ子「バーバラ・リスコフ と学生たち」
やめ太郎「リスコフって,あの?」
ルビ子「そう,『リスコフの置換原則』の人」
やめ太郎「へー」
ルビ子「この人,めちゃめちゃスゴイわ」やめ太郎「で,なんで CLU みたいなマイナーな言語を?」
ルビ子「今のいろんな言語にかなり影響を与えてるみたいやねん」
やめ太郎「たとえば?」
ルビ子「抽象データ型という概念を導入して,のちのオブジェクト指向プログラミングに先駆けたみたい,知らんけど」
やめ太郎「オブジェクト指向のルーツの一つなんか〜」
ルビ子「関数が多値を返したり,複数の変数に多重代入したり,も CLU が先駆やったみたい」
やめ太郎「Ruby とか多重代入あるもんな」
ルビ子「Ruby のは配列を介してて CLU のとは若干違うけど」
やめ太郎「さよか」ルビ子「Ruby にはもっと決定的な影響を与えてんねん」
やめ太郎「どんな?」
ルビ子「もう,これこそが Ruby の利点というような」
やめ太郎「というと?」
ルビ子「ブロック付きメソッド呼び出し」
やめ太郎「確かにそれのおかげでコードが簡潔に書けるもんな(知らんけど)」
ルビ子「メソッド呼び出しのとき,値は引数として渡すけど,そのほかに処理をブロックとして渡すことができる」
やめ太郎「それが CLU 由来なん?」
ルビ子「CLU は繰り返しを抽象化する仕組みとしてイテレーターというものを導入してん」
やめ太郎「疲れーたー」
ルビ子「まいど,おおきに」
やめ太郎「Ruby との関係はどうなん?」
ルビ子「CLU のイテレーターは名前のとおり繰り返しが目的で,for
文でしか使えなかった」
やめ太郎「Ruby のイテレーターとはだいぶちゃうんかな」
ルビ子「matz は CLU のイテレーターと同じようなものを作ろうとしてメソッドにブロックを与えることを考えたみたい」
やめ太郎「それがブロックの由来かあ」
ルビ子「出来てみたら,繰り返しだけじゃなくて,いろいろ使えることが分かったんやね」
やめ太郎「ファイルを開いてなんかするのもブロックやしな」
ルビ子「Ruby が CLU の影響をどんなふうに受けたかは matz の以下の記事が参考になるわ」
Rubyist のための他言語探訪 【第 2 回】 CLU(Rubyist Magazine 0009 号)ルビ子「制御構造の構文にも見るべきところがあるねん」
やめ太郎「どういう?」
ルビ子「Pascal や C,JavaScript とかって,if
の節には〈文〉がつくやん?」
やめ太郎「せやなー」
ルビ子「複数の文からなるコードを与えたいときは?」
やめ太郎「{ }
でくくるんやな」
ルビ子「そう,で,単文のときは{ }
が要らんねんけど,いわゆる ぶら下がり else 問題が起こりうる」
やめ太郎「それって,しゃあないんちゃう?」
ルビ子「いや,Ruby も Rust も Modula-2 もこの問題は起きひんで」
やめ太郎「なんでやのん?」
ルビ子「節は最初から中身が複数の文からなる前提で,終わりを表す記号やキーワードを設けたから」
やめ太郎「具体的にいうと?」
ルビ子「たとえば Ruby はこう」if cond then else endルビ子「Rust ならこう」
if cond { } else { }やめ太郎「Rust の例は C とどこがちゃうねん」
ルビ子「{ }
が省略できないってところね」
やめ太郎「CLU もこういうタイプなわけ?」
ルビ子「そう,上の Ruby の例はそのまんま CLU の例でもある」
やめ太郎「へー,1970 年代の前半に解決済みいうことかあ」
ルビ子「C は CLU より古いけど,Java とか PHP,JavaScript みたいな後発の言語がなんで ALGOL の轍を踏み続けたんか理解に苦しむわ」
やめ太郎「せやなー(知らんけど)」ルビ子「ほかにも,変数が任意の場所で宣言できたりとか」
やめ太郎「そんなん当たりまえちゃうん?」
ルビ子「いや昔の言語は先頭でまとめて宣言せなアカンかったんやて」
やめ太郎「へー」ルビ子「例外処理も当時は画期的やったんやって」
やめ太郎「いま当たり前のいろんなもんが CLU で先駆的に導入されてたんやな」
- 投稿日:2019-06-22T02:40:27+09:00
RubyでTwitterからワードクラウドを作成
はじめに
Twitterのトレンド一覧では、単語しか出てこず、一体何に関する話題なのか分からない。
ということで、トレンドからツイートを取得してワードクラウドを作成することで、一目でどんな話題で盛り上がっているのか可視化しようと思います。せっかちな方のために、先に結果を載せときます。
トレンド"#きのう何食べた" に対する実行結果
使用技術
Ruby: 2.4.1
Mecab: 0.996Twitterからデータを取得
アクセストークンの設定
まず、Twitterにアクセスするためのトークンなどを設定します。
require 'twitter' client = Twitter::REST::Client.new do |config| config.consumer_key = "Consumer Key (API Key)" config.consumer_secret = "Consumer Secret (API Secret)" config.access_token = "Access Token" config.access_token_secret = "Access Token Secret" end参考
https://qiita.com/shimisunet/items/c3a0b93fb13fa82ed8beトレンドの取得
次にトレンドを取得します。
client.trends_place(23424856).take(3).each do |trend| # 23424856:日本のtrend p trend.name endツイートの取得
トレンドのツイートを取得します。
client.search(word, exclude: "retweets").take(count).each do |tweet| p tweet.text end前処理
取得したツイートに対し、
- URLの除去
- 分かち書き (Mecab)
を行います。
URLの除去
Rubyのuriパッケージを利用します。
require 'uri' URI.extract(text).uniq.each {|url| text.gsub!(url, '')}参考
http://thr3a.hatenablog.com/entry/20180315/1521079183分かち書き
Mecabを利用して分かち書きをします。
副詞など、どのツイートにも出てきそうな単語は除去します。require 'mecab' tagger = MeCab::Tagger.new wakati = tagger.parse(text) wakati.delete!("EOS") # 分かち書きの結果に"EOS"が出てくるため除去 wakati = wakati.split("\n") # 単語ごとに分割 words = [] wakati.each do |w| word = w.split("\t") # タブ文字前に単語、後に単語の情報があるため分割 if word[1].include?("形容詞") || word[1].include?("名詞") unless word[0] == "#" # "#"は名詞に分類されるため除去 words.push word[0] end end endワードクラウド作成
解析に入ります。
分かち書きの結果、トレンド内のツイートに出てくる単語を格納した配列を作成します。
それを元にワードクラウドを作成します。magic_cloudの裏側ではImage Magickが動作しており、:font_familyに'Arial Unicode'を指定することで日本語に対応できます。(重要)
require 'magic_cloud' font = 'Arial Unicode' words = words.group_by(&:itself).map{ |key, value| [key, value.count] }.to_h cloud = MagicCloud::Cloud.new(words, rotate: :none, scale: :linear, :font_family=>font) cloud.draw(500, 250).write("#{word}.png")参考
Rubyで配列内の重複する要素を数える方法
https://github.com/zverok/magic_cloud考察
2019年6月22日の夜ごろのトレンド"#きのう何食べた"に対して、以下の結果が得られました。
とりあえず、どんな話題なのか読み取れそうです。
私の考察としては、
- ドラマらしい
- 来週最終回らしい
個人的にはyajuが気になる。といったところです。
- 投稿日:2019-06-22T02:40:27+09:00
Rubyでワードクラウドを用いたTwitterトレンドの可視化
はじめに
Twitterのトレンド一覧では、単語しか出てこず、一体何に関する話題なのか分からない。
ということで、トレンドからツイートを取得してワードクラウドを作成することで、一目でどんな話題で盛り上がっているのか可視化しようと思います。せっかちな方のために、先に結果を載せときます。
トレンド"#きのう何食べた" に対する実行結果
使用技術
Ruby: 2.4.1
Mecab: 0.996Twitterからデータを取得
アクセストークンの設定
まず、Twitterにアクセスするためのトークンなどを設定します。
require 'twitter' client = Twitter::REST::Client.new do |config| config.consumer_key = "Consumer Key (API Key)" config.consumer_secret = "Consumer Secret (API Secret)" config.access_token = "Access Token" config.access_token_secret = "Access Token Secret" end参考
https://qiita.com/shimisunet/items/c3a0b93fb13fa82ed8beトレンドの取得
次にトレンドを取得します。
client.trends_place(23424856).take(3).each do |trend| # 23424856:日本のtrend p trend.name endツイートの取得
トレンドのツイートを取得します。
client.search(word, exclude: "retweets").take(count).each do |tweet| p tweet.text end前処理
取得したツイートに対し、
- URLの除去
- 分かち書き (Mecab)
を行います。
URLの除去
Rubyのuriパッケージを利用します。
require 'uri' URI.extract(text).uniq.each {|url| text.gsub!(url, '')}参考
http://thr3a.hatenablog.com/entry/20180315/1521079183分かち書き
Mecabを利用して分かち書きをします。
副詞など、どのツイートにも出てきそうな単語は除去します。require 'mecab' tagger = MeCab::Tagger.new wakati = tagger.parse(text) wakati.delete!("EOS") # 分かち書きの結果に"EOS"が出てくるため除去 wakati = wakati.split("\n") # 単語ごとに分割 words = [] wakati.each do |w| word = w.split("\t") # タブ文字前に単語、後に単語の情報があるため分割 if word[1].include?("形容詞") || word[1].include?("名詞") unless word[0] == "#" # "#"は名詞に分類されるため除去 words.push word[0] end end endワードクラウド作成
解析に入ります。
分かち書きの結果、トレンド内のツイートに出てくる単語を格納した配列を作成します。
それを元にワードクラウドを作成します。magic_cloudの裏側ではImage Magickが動作しており、:font_familyに'Arial Unicode'を指定することで日本語に対応できます。(重要)
require 'magic_cloud' font = 'Arial Unicode' words = words.group_by(&:itself).map{ |key, value| [key, value.count] }.to_h cloud = MagicCloud::Cloud.new(words, rotate: :none, scale: :linear, :font_family=>font) cloud.draw(500, 250).write("#{word}.png")参考
Rubyで配列内の重複する要素を数える方法
https://github.com/zverok/magic_cloud考察
2019年6月22日の夜ごろのトレンド"#きのう何食べた"に対して、以下の結果が得られました。
とりあえず、どんな話題なのか読み取れそうです。
私の考察としては、
- ドラマらしい
- 来週最終回らしい
個人的にはyajuが気になる。といったところです。
- 投稿日:2019-06-22T02:10:00+09:00
たのしいRuby(第6版) memo
たのしいRuby(第6版)を読んでのメモです。
p and print method
printメソッドは実行結果やメッセージなどを普通に表示したいとき、
pメソッドは実行中のプログラムの様子を確認したいとき、
と使い分ける。magic comment
# encoding: 文字コード
でソースコードの文字コードを指定できる。pメソッドで日本語の文字列を出力すると、
文字化けしたような出力になる場合、
-E 文字コード
の形式でコマンドラインオプションを指定するopal
OpalはRubyのコードをJavaScriptに変換するコンパイラで、
WebブラウザでRubyを実行する環境を作ることもできるrequire method
引数に指定されたライブラリを探して、そのファイルに書かれた内容を読み込む。
読み込みが終わると、requireメソッドの次の行から処理を再開する。require_relativeメソッドは実行するプログラムが置かれたディレクトリを基準としてライブラリを探す
pseudo variables
nil,true,false,selfなどの特定の値を指し示すために予約された名前で
代入することによって値を変更することはできないmultiple substitution
複数の変数への代入を1つの式で行うことができる。
受け取る側の変数に1つだけ「*」を付けておくと、
その変数には余った値の配列が代入される。一時変数を使わない値の入れ替えに使うこともできる。
a, b = 0, 1 a, b = b, a p [a, b] #=> [1, 0]配列を代入するときに左辺に複数の変数があると、
自動的に配列の要素を取り出して多重代入が行われる。
配列の先頭の要素だけを取り出したい場合には下記のようにも書けるary = [1, 2] a, = ary p a #=> 1comparison operator
比較演算子の結果はtrueかfalseとなる
regular expression matching
マッチした場合には文字列中でマッチした部分の位置を、
マッチしなかった場合はnilを返すboolean value of Ruby
真 falseとnilを除くオブジェクト全て 偽 falseとnil trueやfalseを返さないメソッドで、
意味のある値を返せない場合でもnilを返すメソッドであれば、条件判断に利用できるunless statement
条件が偽(false or nil)のときに文を実行する
case statement
比較したいオブジェクトが1つで、
そのオブジェクトの値によって場合分けしたい場合、
case文を使ったほうがわかりやすく見えることがある。
正規表現を用いた場合分けもできる。case文はwhenで指定した値に一致するかどうかを「===」演算子を使って判定する。
「===」は左辺が数値や文字列の場合は「==」と同じ意味を持つが、
正規表現の場合は「=~」と同じようにマッチしたかどうかを判定したり、
クラスの場合は右辺がそのクラスのインスタンスかどうかを判定するなど,
両辺の値を比較するよりも、もう少し緩い意味で同じかどうかを判断するために使うobject_id
すべてのオブジェクトはアイデンティティと値を持っている。
オブジェクトのIDはobject_id(or id)メソッドで得ることができる。
2つのオブジェクトが同じかどうか(IDが同じかどうか)はequal?で判定できる。
オブジェクトではなく、値が等しいかどうかを調べるには「==」を使う。値が同じかどうかを判定するメソッドとしてeql?もあり、
たいていは同じように振る舞うが、数値クラスで再定義されているので、
異なる振る舞いをする。
多少厳密に比較を行う必要がある場合に使う。
例えば、ハッシュのキーとして、0と0.0は別のものとして扱われるが、
ハッシュオブジェクトの内部ではeql?メソッドを使ってキーの比較が行われているuntil statement
while文は条件が成立している間は繰り返すのに対して、
until文は条件が成立するまで繰り返すfor statement
for文はRubyの内部処理としてはeachメソッドが実行される特殊な構文になっている。
したがって、eachメソッドを呼び出すことができるオブジェクトであれば、
for文のinのあとに指定することができるblocked method call
オブジェクト.メソッド名(引数, ・・・) do |変数1, 変数2, ・・・| ブロックの内容 endor
オブジェクト.メソッド名(引数, ・・・) {|変数1, 変数2, ・・・| ブロックの内容 }ブロックの最初の「| 〜 |」で囲まれた部分に指定された変数は
ブロック変数またはブロックパラメータという。
この変数にはブロックを実行するたびに、メソッドからパラメータが渡される。
パラメータの数や値はメソッドごとに異なるno receiver method
Rubyではレシーバを記述せずに使えるメソッドを関数的メソッドと呼ぶこともある。
実際にレシーバに該当するオブジェクトがないわけではなく、
それが省略されている。
関数的メソッドはレシーバの状態によって結果が変わることがないように作られている。
(例えば、printやsleepメソッド)variable length argument
引数の数が決められないメソッドは、
「変数名」の形式で定義し、与えられた引数をまとめて配列として得られる。
「変数名」の形式の引数はメソッド定義の引数リストに1つだけ含めることができるkeyword argument
キーワード引数を使うと引数名と値をペアで引数として渡せるようになる。
「引数名: 値」の形式でデフォルト値も指定できる。
デフォルト値を指定したくない場合は、「引数名: 」と引数名だけ書く。
デフォルト値が省略された引数は呼び出し時に省略できない。定義に存在しないキーワード引数をエラーにせずに受け取りたい場合は
「**変数名」の形式で受け取るdef meth(x: 0, y: 0, z: 0, **args) [x, y, z, args] end p meth(z: 4, y: 3, x: 2) #=> [2, 3, 4, {}] p meth(x: 2, z: 3, v: 4, w: 5) #=> [2, 0, 3, {:v=>4, :w=>5}}引数argsには、引数リストに存在しないキーワードをキーとして
ハッシュオブジェクトが設定される。キーワード引数は通常の引数と組み合わせて用いることができる。
def func(a, b: 1, c: 2) ︙ endaは必須、b,cはキーワード引数となり、
呼び出し時は
func(1, b: 2, c: 3)
のように最初の引数に続けて、キーワード引数を指定する。ハッシュをキーワード引数として渡すことができる。
キーはシンボルである必要があるinstance_of?, is_a?
instance_of?はクラスのインスタンスであることを調べることができ、
is_a?は継承関係をさかのぼってクラスに属するかどうかを調べることができる。
スーパークラスを指定せずに定義したクラスは
Objectクラスの直接のサブクラスとなるself variables
インスタンスメソッドの中で、
メソッドのレシーバ自身を参照するにはselfという特殊な変数を使うprivate
レシーバを指定して呼び出せないメソッドにする。
レシーバを省略した形式でしか呼べないため、インスタンスの外側から利用できなくなる。
何も指定せずに定義されたメソッドはpublicになるが、
initializeメソッドだけは常にprivateとして定義されるmodule
クラスとモジュールは下記の点が異なる。
・モジュールはインスタンスを持つことができない。
・モジュールは継承できない。モジュールの提供するメソッドは「モジュール名.メソッド名」という形式で参照する。
このような形式で使用するメソッドをモジュール関数という。
モジュール内で定義されたメソッドや定義と同名のものが定義されていない場合、
モジュール名の指定を省略できる。
includeを使えば、モジュールが持っているメソッドや定数名を
現在の名前空間に取り込むことができる。
また、クラスにモジュールを追加して複数のクラスでモジュールの機能を共有できるメソッドをモジュール関数として外部に公開するにはmodule_functionを使う必要がある
Enumarable
Ruby標準の組み込みの機能で、
Mix-inにより機能を提供することができるモジュールprepend method
Mix-inされたクラスでのメソッドよりも
モジュールのメソッドを優先することができるextend method
extendメソッド(Object#extend)はモジュールで定義されたすべてのメソッドを
特異メソッドとしてオブジェクトに追加することができる。
モジュールを特異クラスにインクルードして、
オブジェクトにモジュールの機能を追加するassignment operator
「+」と「=」を組み合わせて、「+=」とするように
二項演算子と代入を組み合わせた演算子。
「=」は右側logical operator
・左側の式から順に評価される
・論理式の真偽が決定すると、残りの式は評価されない
・最後に評価された式の値が論理式全体の値となるsafe navigation operator(&. method)
nilチェック付きのメソッド呼び出すを行うことができる。
レシーバのオブジェクトがnilの場合はnilを返す。RailsのActiveSupportにtryというメソッドがあるが、
&.の場合は呼び出そうとしているメソッドが定義されていない場合はエラーになる。
これはtryメソッドがrespond_to?でチェックしているため。
ちなみに、Rails6あたりから、
tryメソッドの内部でtry!メソッドを呼び出すのはやめるのかも
(https://github.com/rails/rails/commit/ba7d1265e3f2755f55243f32c0264c5c20e01610#diff-ed128222705b72beebd1daae7a6be237)exception handling
例外処理にはbegin〜rescue〜end文を使用する。
rescueに続けて変数名を指定することで例外オブジェクトを得ることができる。
例外オブジェクトはclass,message,backtraceといったメソッドを持つ。begin 例外を発生させる可能性のある処理 rescue => 例外オブジェクトが代入される変数 例外が起こった場合の処理 endまた、rescue節で補足する例外を指定することもできる。
メソッドの処理全体をbegin〜endでくくる場合はbeginとendを省略して、
rescue節やensure節を書くことができる。ちなみに、rescueは修飾子として使うこともできる
例外を発生させる可能性のある処理 rescue 例外が起こった場合の処理
exception class
すべての例外はExceptionクラスのサブクラス。
rescue節で例外クラスを指定しなかった場合は
ExceptionのサブクラスであるStandardErrorとそのサブクラスが補足される。
自分で例外クラスを定義する場合は
StandardErrorクラスを継承したクラスを作り、さらにそれを継承するのが一般的とのことraise an exception
自分で例外を発生させるにはraiseメソッドを使う。
raise メッセージ
(StandardErrorクラスのサブクラスである)RuntimeErrorを発生させる。
新しく生成された例外オブジェクにメッセージとして文字列をセットするraise 例外クラス
指定した例外を発生させるraise 例外クラス、メッセージ
指定した例外を発生させ、
新しく生成された例外オブジェクにメッセージとして文字列をセットするraise
rescue節の外ではRuntimeErrorを発生させ、
rescue節の中では最後に発生した例外($!)をもう一度発生させるx.divmod(y)
xをyで割ったときの商と余りを配列にして返す
securerandom library
安全な乱数を生成させるモジュールを提供
%Q, %q
「"」と「'」を含めた文字列を作りたいときは
「\"」「\'」などの特殊文字を使うよりも、%Qや%qを使うと簡単desc = %Q{Rubyの文字列には「''」も「""」も使われます。} str = %q|Ruby said, 'Hello world!!'|Here documents
改行を含む長い文字列を作りたい場合は便利。
<<の後ろには終了の記号として" "か' 'で囲った文字列を書く。
インデントを揃えたいときは「<<」の代わりに「<<-」を使う。5.times do |i| print(<<-"EOB") i: #{i} EOB end上記の結果
i: 0 i: 1 i: 2 i: 3 i: 4「<<~」を使うと行頭の空白が切り詰められる
5.times do |i| print(<<~"EOB") i: #{i} EOB end上記の結果
i: 0 i: 1 i: 2 i: 3 i: 4running OS command
`ls -al`each_line code example
each_lineメソッドを使って繰り返し新しい行を読み込む場合には、
chomp!メソッドなどで破壊的に改行文字を落とすという方法があるf.each_line do |line| line.chomp! # lineを処理 endstring code conversion
encodeメソッドを使う
str = '文字列' str.encode('utf-8') p str.encodingHash#fetch
Hashの値の取り出しに使える。
第2引数を指定すれば、キーが登録されていないときに返す値として使用できるh = Hash.new h.store('R', 'Ruby') p h.fetch('R', '(undef)') #=> "Ruby" p h.fetch('N', '(undef)') #=> "(undef)"creating a Hash with default values by block
キーによって異なる値を返したい場合や、
すべてのキーに対する値が同じオブジェクトになることを避けたい場合には、
Hash.newにブロックを指定するh = Hash.new do |hash, key| hash[key] = key.upcase end h['a'] = 'b' p h['a'] #=> "b" p h['x'] #=> "X" p h['y'] #=> "Y"merging hashes
p ({'a': 'x'}.merge({'b': 'y'})) #=> {:a=>"x", :b=>"y"}%r (regular expression)
%rを使って正規表現のオブジェクトを作ることができる。
正規表現中に「/」の文字を使いたいときに便利%r(pattern) %r<pattern> %r|pattern| %r{pattern}matching of head and end
行頭が「^」、行末が「$」でマッチングする。
例えば、「^ABC」というパターンは「"012\nABC"」という文字列にもマッチする。
文字列の先頭は「\A」、文字列の末尾「\z」matching with any character
「.」は任意の1文字とマッチ
repeating pattern
・「*」は0回以上の繰り返し
・「+」は1回以上の繰り返し
・「?」は0回または1回の繰り返し
・「{n}」はn回の繰り返し
・「{n, m}」はn〜m回の繰り返し最短マッチでは
・「*?」は0回以上の繰り返しのうち最短部分
・「+?」は1回以上の繰り返しのうち最短部分regular expression options
・「i」はアルファベットの大文字・小文字の違いを無視
・「x」は正規表現内の空白と「#」の後ろの文字を無視
・「m」は「.」が改行文字にもマッチRegexp.newメソッドでは第2引数にオプション定数を指定できる(複数可)
Regexp.new('Rubyスクリプト', Regexp::EXTENDED) Regexp.new('Rubyスクリプト', Regexp::IGNORECASE | Regexp::MULTILINE) p Regexp::EXTENDED #=> 2 p Regexp::IGNORECASE #=> 1 p Regexp::MULTILINE #=> 4capturing groups in regular expression
$数字の形の変数でマッチした部分の一部を取り出せる。
「(?: )」でキャプチャする必要がないパターンをまとめることもできる。$数字以外にも
「\$`」でマッチした部分よりも前の文字列、
「\$&」でマッチした部分そのものの文字列、
「\$'」でマッチした部分より後ろの文字列などを取りだすことができるsub method and gsub method
subメソッドは最初にマッチ部分だけ、
gsubメソッドはマッチする部分すべてを書き換えるscan method
パターンにマッチした部分を取り出す(置き換えない)。
マッチした部分になんらかの処理を行うときに使う'abracatabra'.scan(/.a/) do |matched| p matched end上記を実行すると
"ra" "ca" "ta" "ra"また、正規表現の中で「()」が使われていると、
そこにマッチした部分を配列にして返し、
ブロックの変数を「()」の数だけ並べると、
配列ではなくそれぞれの要素を取り出すことができる。ブロックがない場合はマッチした文字列の配列を返す
standard input
標準入力はデータを受け取るためのIOオブジェクト。
組み込み定数STDINに割り当てられているほか、
グローバル変数$stdinからも参照されている。
レシーバを指定しないgetsなどのメソッドは$stdinからデータを受け取る。
標準入力の最初はコンソールに関連付けられていて、キーボード入力を受け取るstandard output
標準出力はデータを出力するためのIOオブジェクト。
組み込み定数STDOUTに割り当てられているほか、
グローバル変数$stdoutからも参照されている。
レシーバを指定しないputs,print,printfなどのメソッドは$stdoutへ出力する。
標準出力の最初はコンソールに関連付けられているstandard error
標準エラー出力は警告やエラーを出力するためのIOオブジェクト。
組み込み定数STDERRに割り当てられているほか、
グローバル変数$stderrからも参照されている。
警告メッセージを表示するためにwarnメソッドが$stderrへ出力する。
標準エラー出力も最初はコンソールに関連付けられているinput operation
io.gets(rs)
io.each(rs)
io.each_line(rs)
is.readlines(rs)
IOオブジェクトioからデータを1行読み込む。
行の区切りは引数rsで指定した文字列になるが、
引数が省略された場合は組み込み変数$(default "\n")が行の区切りとなる。これらのメソッドは行の末尾の改行を含む文字列を返す。
文字列の末尾の改行文字を削除するにはchomp!メソッドが便利getsメソッドやeach_lineメソッドを使って、行単位で読み込みを行うと、
それまでに何行読み込んだかが自動的に記録される。
その行数はlinenoメソッドで取得できるbinary mode and text mode
テキストモードは改行文字の変換が有効で、
バイナリモードは変換を行わないzip file reading
zipに圧縮されたデータを読むときはzcatコマンドに展開してもらったデータを受け取ると便利で、
そのコマンドをIO.popenに記述すると
コマンド結果として標準出力に出力したデータをIOオブジェクトから受けることができるstringio library
StringIOオブジェクトへの出力は実際にはどこへも出力されず、
オブジェクトの中に蓄えられ、あとからreadメソッドなどで読み出せる。StringIOオブジェクトはすでに文字列として持っているデータを
IOオブジェクトのように見せかけることもできる。
巨大なデータはいったんファイルに保存し、そうでないデータはそのまま別の処理へ渡すという場合、
StringIOオブジェクトを使うと、IOオブジェクトか文字列かによって処理を分けなくて済む。
(例えば、open-uriライブラリでURIを開いたときに返されるオブジェクトは、
IOオブジェクトかStringIOオブジェクトなので、それぞれのオブジェクト毎の記述をしなくて済む)fileutils library
fileutilsライブラリを読み込むことにより、
FileUtils.cp(ファイルのコピー)やFileUtils.mv(ファイルの移動)など、
ファイルを操作するメソッドを使用することができる。FileUtils.mvを使うと、File.renameメソッドではできないファイルシステムやドライブをまたがったファイルの移動ができる
Dir.open example
Dir.openやFile.openはブロックを与えることによって、
closeメソッドの呼び出しを省略する。Dir.open('/usr/local/lib/ruby/2.6.1') do |dir| dir.each do |name| p name end enddir.read method
Dir#readメソッドを実行すると、最初に開いたディレクトリに含まれるものの名前を1つ順に返す。
ここで読み出せるものは基本的に次の4種類のいずれか
・カレントディレクトリを表す「.」
・親ディレクトリを表す「..」
・その他のディレクトリ名
・ファイル名Dir.glob method
Dir.globメソッドを使うと、シェルのように「」と「?」などのパターンを使ってファイル名を取得できる。
Dir.globメソッドはパターンにマッチしたパス名(ファイル名およびディレクトリ名)を配列にして返す。
カレントディレクトリにあるすべての隠しファイル名はDir.glob('.')で取得できるFile.basename(path[, suffix])
パス名pathのうち、一番後ろの'/'以降の部分を返す。
拡張子suffixが指定された場合は戻り値から拡張子の部分が取り除かれるFile.split(path)
パス名pathをディレクトリ名の部分とファイル名の部分に分解し、
2つの要素からなる配列を返す。多重代入を使って受け取ると便利dir, base = File.split('/usr/local/bin/ruby') p dir #=> "/usr/local/bin" p base #=> "ruby"File.expand_path(path[, default_dir])
相対パス名pathをディレクトリ名default_dirに基づいて絶対パス名に変換する
find library
findライブラリに含まれるFindモジュールは
指定したディレクトリ以下に存在するディレクトリやファイルを再帰的に処理することができるrequire 'find' IGNORES = [ /^\./, /^\.svn$/, /^\.git$/ ] def listdir(top) Find.find(top) do |path| if File.directory?(path) dir, base = File.split(path) IGNORES.each do |re| if re =~ base Find.prune end end puts path end end end listdir(ARGV[0])FileUtils.mkdir_p(path)
階層の深いディレクトリも一度に作成できる。
pathを配列にして複数のディレクトリを作成することも可能
- 投稿日:2019-06-22T01:27:53+09:00
ActiveSupport::TimeZoneを0オフセットでインスタンス化すると1時間ずれる
指定したオフセット値(JSTなら9時間)で
ActiveSupport::TimeZone
を作り、それをもとにActiveSupport::TimeWithZone
インスタンスを作りたい。jst = ActiveSupport::TimeZone[9] # => #<ActiveSupport::TimeZone:0x00007fbbe3b034b0 @name="Osaka", @utc_offset=nil, @tzinfo=#<TZInfo::TimezoneProxy: Asia/Tokyo>> jst.now # => Fri, 21 Jun 2019 21:24:26 JST +09:00+9は、問題なし。
utc = ActiveSupport::TimeZone[0] # => #<ActiveSupport::TimeZone:0x00007fbbe3afb030 @name="Casablanca", @utc_offset=nil, @tzinfo=#<TZInfo::TimezoneProxy: Africa/Casablanca>> utc.now # => Fri, 21 Jun 2019 13:25:48 WEST +01:00 utc.tzinfo.current_period.utc_offset # => 0ファッ!?
+00:00
が期待されるところ+01:00
となっている!?
TZInfoのutc_offsetは0を指しているようだが...そもそもoffsetだけではtimezoneと言えないのでやろうとしていることが強引な気もするが、それはさておき、どうやるのが正解なのだろうか。
関係ありそうだが、詳しくは読んでない。
https://github.com/tzinfo/tzinfo/issues/98
動作確認環境
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-darwin16]
activesupport (5.2.1)
tzinfo (1.2.5)
- 投稿日:2019-06-22T00:54:03+09:00
Railsの起動エラーとMySQLのエラー解除方法(個人メモ)
Railsの起動エラーと、MySQLのエラー解除方法を個人的にメモする。
【PC:MacBookPro2012(13-inch, Mid 2012)、MacOS Mojave 10.14.4】
【ruby 2.3.7p456 (2018-03-28 revision 63024) [universal.x86_64-darwin18]】
【Rails 5.2.3】
【mysql Ver 8.0.15 for osx10.14 on x86_64 (Homebrew)】MySQLのエラーについて。
まずはmysqlの場所を確認。
$ which mysql /usr/local/bin/mysqlMySQLサーバーを起動させる。
$ mysql.server start Starting MySQL ...... ERROR! The server quit without updating PID file (/usr/local/var/mysql/*****.local.pid).PIDファイルを確認する。
$ ls -la /usr/local/var/mysql/*****.local.pid ls: /usr/local/var/mysql/*****.local.pid: No such file or directoryMySQLサーバーをストップしてみる。
$ mysql.server stop ERROR! MySQL server PID file could not be found!sudoを入れて起動してみる。
$ sudo mysql.server start Password: Starting MySQL . ERROR! The server quit without updating PID file (/usr/local/var/mysql/*****.local.pid).安全にMySQLを起動してみる。
$ mysqld_safe 2019-04-24T03:34:24.6NZ mysqld_safe Logging to '/usr/local/var/mysql/*****.local.err'. 2019-04-24T03:34:24.6NZ mysqld_safe Starting mysqld daemon with databases from /usr/local/var/mysql 2019-04-24T03:34:29.6NZ mysqld_safe mysqld from pid file /usr/local/var/mysql/*****.local.pid endedとりあえずアンインストールしてみる。
$ brew uninstall mysql Uninstalling /usr/local/Cellar/mysql/8.0.15... (267 files, 234.6MB)ちゃんと削除できたか確認。
$ which mysql (何も出てこない)再度インストールしてみる。
$ brew install mysqlこれでmysql.server startしてもエラーだったので、上の操作を繰り返してみたけどダメ。
「PIDファイルが見つからない」ので、ファイルの生成をしてみる。
$ /usr/local/var/mysql/mysql > touch /usr/local/var/mysql/*****.local.pid -bash: /usr/local/var/mysql/mysql: is a directory奇跡的に起動しないか願いを込めて。
$ mysql.server start Starting MySQL ...... ERROR! The server quit without updating PID file (/usr/local/var/mysql/*****.local.pid).どこかで見つけたこのコマンドを入力してみる。
$ /usr/local/var/mysql/mysql > sudo mysql.server restart -bash: /usr/local/var/mysql/mysql: is a directory同じかい!!(ノ_<)
$ sudo chown -R _mysql:_mysql /usr/local/var/mysql /tmp/mysql.sock Password:何やらパスワードを求められた。。。いけるのか?
sudoで起動させてみよう。
$ sudo mysql.server start Starting MySQL ..... ERROR! The server quit without updating PID file (/usr/local/var/mysql/*****.local.pid).あかんのかい!(T . T)
sudoなしで起動できるようにするらしいコマンド。
$ sudo chown -R `whoami`:admin /usr/local/var/mysql /tmp/mysql.sock起動させてみる。
$ mysql.server start Starting MySQL .. SUCCESS!キターーーーーーーーー!!!!!!♪───O(≧∇≦)O────♪
よーし!早速Railsをローカル環境で表示させてみよう。Railsのシステムを起動。
$ rails sブラウザでlocalhost:3000を入力。(成功なら画面にRailsの初期画面が表示される)
なんとエラー!!恐怖の赤い画面!!
ActiveRecord::NoDatabaseError (Unknown database 'hello_sample7_development'):
え、データベースがない・・・?∑(゚Д゚)ということでデータベースを作成。
$ rails db:create Created database 'ファイル名_development' Created database 'ファイル名_test'再度Railsのシステム起動。
$ rails sRailsの初期画面が出た!!!☆:.。. o(≧▽≦)o .。.:☆