- 投稿日:2019-07-30T23:25:19+09:00
Ruby/Gtkの文字入力に自動補完機能をつける方法(Gladeなし縛り)
キーボード入力はミスが多い。
マウス入力は選択肢を見つける時間がもったいない。
そこで輝くのが「キーボードで絞り込んで、マウスで選択」という自動補完機能。
日本語情報が非常に少なかったので、投稿しておきます。0:やりたい事
「["Tokyo","Yamagata","Yamaguchi","Yamanashi"]」という配列を渡し、
入力欄に「Y」と入れたら「["Yamagata","Yamaguchi","Yamanashi"]」の三択になり、
「Yaman」と入れたら「Yamanashi」一択になり、
「Yamanasi」(h忘れ)で0択になる。縛り
Gtk3(3.3.6)のみ。Gladeは不使用で行きます。
筆者はWindows環境なので、Gladeを導入するだけで半泣きになりました。1:まずは入力欄作成
Gtk::WindowとGtk::Entryを併用して無機能の入力欄を作ります。
ここまでは日本語情報もまあまああります。auto_completion_sample.rbrequire "gtk3" class WindowSample < Gtk::Window def initialize super entry_sample=EntrySample.new#テキストエントリウィジェットを作成 self.add(entry_sample)#ウィンドウにテキストエントリを追加する self.signal_connect('delete_event') {Gtk.main_quit()}#「このウィンドウが閉じられたらコード終了」の意味 # この仕様があるせいで、最低一個はウィンドウを作る必要がある。全てダイアログのみのGUIを作る事は多分できない end end class EntrySample < Gtk::Entry def initialize() super array_sample=["Tokyo","Yamagata","Yamaguchi","Yamanashi"]#入力候補 ####ここに自動補完処理を書く#### end end window_sample= WindowSample.new()#ウィンドウを作成 window_sample.show_all() Gtk::main()若干コメントが多くてくどいですが、これは筆者のコーディングレベルに合わせたからです。
実行結果
白背景に白テキストエントリで見えづらいですね……。
当然、現段階では入力候補は何も出てきません。2:ListStoreとは
GtkにはTreeModelというクラスがあります。どういうクラスなのかは……
よくわかりませんでした。誰か教えて下さい。
さてコメント稼ぎも済んだ所で、TreeModelクラスの一種にListStoreクラスがあります。
これは表(行列)のようなデータを扱うためのクラスです。
(詳しく知りたい人はTreeViewとかでググってください。ListStoreをTreeViewで表示する方法は、Qiita含めて日本語情報が結構あります。)
入力候補配列を、このListStoreクラスにします。auto_completion_sample.rbrequire "gtk3" class WindowSample < Gtk::Window def initialize super entry_sample=EntrySample.new#テキストエントリウィジェットを作成 self.add(entry_sample)#ウィンドウにテキストエントリを追加する self.signal_connect('delete_event') {Gtk.main_quit()}#「このウィンドウが閉じられたらコード終了」の意味 # この仕様があるせいで、最低一個はウィンドウを作る必要がある。全てダイアログのみのGUIを作る事は多分できない end end class EntrySample < Gtk::Entry def initialize() super array_sample=["Tokyo","Yamagata","Yamaguchi","Yamanashi"]#入力候補 store_sample = Gtk::ListStore.new(String)#「表は横一列。文字列のみ」と宣言。整数が2列だと(Integer,Integer)とかになる array_sample.each do |element_sample| store_sample.append[0]=element_sample#ListStoreの一番下に行を追加し、そのインデックスは0の列に配列の要素を代入。 #エクセルと違い、ListStoreの列は0から始まります。 end ####これでListStore完成#### end end window_sample= WindowSample.new()#ウィンドウを作成 window_sample.show_all() Gtk::main()3:EntryCompletionとは
GtkにはEntryCompletionというクラスがあります
こちらは簡単ですね。テキストエントリの補完に使います。
そして、EntryCompletionクラスには「model」プロパティと「text_column」プロパティの2つを指定する必要があり、
このうち「model」プロパティはTreeModelクラスしか代入できません。
さっき配列をListStoreクラスにしたのはこれが理由です。auto_completion_sample.rbrequire "gtk3" class WindowSample < Gtk::Window def initialize super entry_sample=EntrySample.new#テキストエントリウィジェットを作成 self.add(entry_sample)#ウィンドウにテキストエントリを追加する self.signal_connect('delete_event') {Gtk.main_quit()}#「このウィンドウが閉じられたらコード終了」の意味 # この仕様があるせいで、最低一個はウィンドウを作る必要がある。全てダイアログのみのGUIを作る事は多分できない end end class EntrySample < Gtk::Entry def initialize() super array_sample=["Tokyo","Yamagata","Yamaguchi","Yamanashi"]#入力候補 store_sample = Gtk::ListStore.new(String)#「表は横一列。文字列のみ」と宣言。整数が2列だと(Integer,Integer)とかになる array_sample.each do |element_sample| store_sample.append[0]=element_sample#ListStoreの一番下に行を追加し、そのインデックスは0の列に配列の要素を代入。 #エクセルと違い、ListStoreの列は0から始まります。 end completion_sample= Gtk::EntryCompletion.new#作成して、 completion_sample.model=store_sample#ListStoreを代入して、 completion_sample.text_column=0#「ListStoreのうちインデックス0の列を使ってくださいね」と指定。一列しかないのになぜか必要。 ####これでcompletionも用意完了#### end end window_sample= WindowSample.new()#ウィンドウを作成 window_sample.show_all() Gtk::main()4:Entry.Comletionに代入
いよいよラスト一行。
EntryCompletionをEntry.comletionに代入します。auto_completion_sample.rbrequire "gtk3" class WindowSample < Gtk::Window def initialize super entry_sample=EntrySample.new#テキストエントリウィジェットを作成 self.add(entry_sample)#ウィンドウにテキストエントリを追加する self.signal_connect('delete_event') {Gtk.main_quit()}#「このウィンドウが閉じられたらコード終了」の意味 # この仕様があるせいで、最低一個はウィンドウを作る必要がある。全てダイアログのみのGUIを作る事は多分できない end end class EntrySample < Gtk::Entry def initialize() super array_sample=["Tokyo","Yamagata","Yamaguchi","Yamanashi"]#入力候補 store_sample = Gtk::ListStore.new(String)#「表は横一列。文字列のみ」と宣言。整数が2列だと(Integer,Integer)とかになる array_sample.each do |element_sample| store_sample.append[0]=element_sample#ListStoreの一番下に行を追加し、そのインデックスは0の列に配列の要素を代入。 #エクセルと違い、ListStoreの列は0から始まります。 end completion_sample= Gtk::EntryCompletion.new#作成して、 completion_sample.model=store_sample#ListStoreを代入して、 completion_sample.text_column=0#「ListStoreのうちインデックス0の列を使ってくださいね」と指定。一列しかないのになぜか必要。 self.completion=completion_sample#完成したEntryCompletionをエントリのcompletionプロパティに代入 end end window_sample= WindowSample.new()#ウィンドウを作成 window_sample.show_all() Gtk::main()5:実行確認とリファクタリング
挙動は完璧。
あとはこのカッコ悪い手続き型コードをリファクタリングするだけですが、
筆者はRuby歴2ヶ月のエクセルおじさんなので勘弁してください。筆者の結論
良い子のみんなはGladeを使いましょう。
- 投稿日:2019-07-30T23:25:19+09:00
Ruby/Gtkの文字入力欄に自動補完を設定する方法(Gladeなし縛り)
キーボード入力はミスが多い。
マウス入力は選択肢を見つける時間がもったいない。
そこで輝くのが「キーボードで絞り込んで、マウスで選択」という自動補完機能。
日本語情報が非常に少なかったので、投稿しておきます。0:やりたい事
「["Tokyo","Yamagata","Yamaguchi","Yamanashi"]」という配列を渡し、
入力欄に「Y」と入れたら「["Yamagata","Yamaguchi","Yamanashi"]」の三択になり、
「Yaman」と入れたら「Yamanashi」一択になり、
「Yamanasi」(h忘れ)で0択になる。縛り
Gtk3(3.3.6)のみ。Gladeは不使用で行きます。
筆者はWindows環境なので、Gladeを導入するだけで半泣きになりました。1:まずは入力欄作成
Gtk::WindowとGtk::Entryを併用して無機能の入力欄を作ります。
ここまでは日本語情報もまあまああります。auto_completion_sample.rbrequire "gtk3" class WindowSample < Gtk::Window def initialize super entry_sample=EntrySample.new#テキストエントリウィジェットを作成 self.add(entry_sample)#ウィンドウにテキストエントリを追加する self.signal_connect('delete_event') {Gtk.main_quit()}#「このウィンドウが閉じられたらコード終了」の意味 # この仕様があるせいで、最低一個はウィンドウを作る必要がある。全てダイアログのみのGUIを作る事は多分できない end end class EntrySample < Gtk::Entry def initialize() super array_sample=["Tokyo","Yamagata","Yamaguchi","Yamanashi"]#入力候補 ####ここに自動補完処理を書く#### end end window_sample= WindowSample.new()#ウィンドウを作成 window_sample.show_all() Gtk::main()若干コメントが多くてくどいですが、これは筆者のレベルに合わせたからです。
実行結果
白背景に白テキストエントリで見えづらいですね……。
当然、現段階では入力候補は何も出てきません。2:ListStoreとは
GtkにはTreeModelというデータ型があります。どういうデータ型なのかは……
よくわかりませんでした。誰か教えて下さい。
さてコメント稼ぎも済んだ所で、TreeModelの一種にListStoreがあります。
これはエクセルよろしく表(行列)のようなデータを扱うための型です。
(詳しく知りたい人はTreeViewとかでググってください。TreeViewについてはQiita含めて日本語情報が結構あります。)
入力候補配列を、このListStore型にします。auto_completion_sample.rbrequire "gtk3" class WindowSample < Gtk::Window def initialize super entry_sample=EntrySample.new#テキストエントリウィジェットを作成 self.add(entry_sample)#ウィンドウにテキストエントリを追加する self.signal_connect('delete_event') {Gtk.main_quit()}#「このウィンドウが閉じられたらコード終了」の意味 # この仕様があるせいで、最低一個はウィンドウを作る必要がある。全てダイアログのみのGUIを作る事は多分できない end end class EntrySample < Gtk::Entry def initialize() super array_sample=["Tokyo","Yamagata","Yamaguchi","Yamanashi"]#入力候補 store_sample = Gtk::ListStore.new(String)#「表は横一列。文字列のみ」と宣言。整数が2列だと(Integer,Integer)とかになる array_sample.each do |element_sample| store_sample.append[0]=element_sample#ListStoreの一番下に行を追加し、そのインデックスは0の列に配列の要素を代入。 #エクセルと違い、ListStoreの列は0から始まります。 end ####これでListStore完成#### end end window_sample= WindowSample.new()#ウィンドウを作成 window_sample.show_all() Gtk::main()3:EntryCompletionとは
GtkにはEntryCompletionというデータ型があります。どういうデータ型なのかは……
こちらは簡単ですね。テキストエントリの補完に使います。
そして、EntryCompletionは「model」プロパティと「text_column」プロパティの2つを指定する必要があり、
このうち「model」プロパティはTreeModel型しか代入できません。
さっき配列をListStoreにしたのはこれが理由です。auto_completion_sample.rbrequire "gtk3" class WindowSample < Gtk::Window def initialize super entry_sample=EntrySample.new#テキストエントリウィジェットを作成 self.add(entry_sample)#ウィンドウにテキストエントリを追加する self.signal_connect('delete_event') {Gtk.main_quit()}#「このウィンドウが閉じられたらコード終了」の意味 # この仕様があるせいで、最低一個はウィンドウを作る必要がある。全てダイアログのみのGUIを作る事は多分できない end end class EntrySample < Gtk::Entry def initialize() super array_sample=["Tokyo","Yamagata","Yamaguchi","Yamanashi"]#入力候補 store_sample = Gtk::ListStore.new(String)#「表は横一列。文字列のみ」と宣言。整数が2列だと(Integer,Integer)とかになる array_sample.each do |element_sample| store_sample.append[0]=element_sample#ListStoreの一番下に行を追加し、そのインデックスは0の列に配列の要素を代入。 #エクセルと違い、ListStoreの列は0から始まります。 end completion_sample= Gtk::EntryCompletion.new#作成して、 completion_sample.model=store_sample#ListStoreを代入して、 completion_sample.text_column=0#「ListStoreのうちインデックス0の列を使ってくださいね」と指定。一列しかないのになぜか必要。 ####これでcompletionも用意完了#### end end window_sample= WindowSample.new()#ウィンドウを作成 window_sample.show_all() Gtk::main()4:Entry.Comletionに代入
いよいよラスト一行。
EntryCompletionをEntry.comletionに代入します。auto_completion_sample.rbrequire "gtk3" class WindowSample < Gtk::Window def initialize super entry_sample=EntrySample.new#テキストエントリウィジェットを作成 self.add(entry_sample)#ウィンドウにテキストエントリを追加する self.signal_connect('delete_event') {Gtk.main_quit()}#「このウィンドウが閉じられたらコード終了」の意味 # この仕様があるせいで、最低一個はウィンドウを作る必要がある。全てダイアログのみのGUIを作る事は多分できない end end class EntrySample < Gtk::Entry def initialize() super array_sample=["Tokyo","Yamagata","Yamaguchi","Yamanashi"]#入力候補 store_sample = Gtk::ListStore.new(String)#「表は横一列。文字列のみ」と宣言。整数が2列だと(Integer,Integer)とかになる array_sample.each do |element_sample| store_sample.append[0]=element_sample#ListStoreの一番下に行を追加し、そのインデックスは0の列に配列の要素を代入。 #エクセルと違い、ListStoreの列は0から始まります。 end completion_sample= Gtk::EntryCompletion.new#作成して、 completion_sample.model=store_sample#ListStoreを代入して、 completion_sample.text_column=0#「ListStoreのうちインデックス0の列を使ってくださいね」と指定。一列しかないのになぜか必要。 self.completion=completion_sample#完成したEntryCompletionをエントリのcompletionプロパティに代入 end end window_sample= WindowSample.new()#ウィンドウを作成 window_sample.show_all() Gtk::main()5:実行確認とリファクタリング
挙動は完璧。
あとはこのカッコ悪い手続き型コードをリファクタリングするだけですが、
筆者はRuby歴2ヶ月のエクセルおじさんなので勘弁してください。筆者の結論
これだけの事を調べるのに20時間とかかけても何の意味もありません。
良い子のみんなはGladeを使いましょう。
- 投稿日:2019-07-30T23:19:18+09:00
Rubyワンライナーメモ : 文字列の先頭を小文字にする
1ライナーで完結する書き方をやってる人が検索で出てこなかったので。
tapとsub!を組み合わせると出来ます。downcase.rb"HogeHoge".tap{ |s| s.sub!(s[0], s[0].downcase) }
- 投稿日:2019-07-30T23:01:33+09:00
RailsのMVCをまとめてみる
はじめに
RailsはMVCアーキテクチャを採用しています。
MVCアーキテクチャに基づき、Railsはどのような流れで処理を行っているのかを確認していこうと思います。注意すること
調べていて分かったことなのですが、どうやら
RailsはMVCではない
のだそうです。正しくは
RailsはMVC2である
そうです。
(Model2MVCやModel2など、他にも呼び方があるみたいです)「Rails MVC」と「MVC」で検索して理解を深めようとした結果、
分かったような分かっていないような
というモヤモヤした気持ちになった方もいるのではないでしょうか。今回はMVCとMVC2の違いについてはまとめませんが、
MVC?あぁRailsのやつだよね?
という理解は厳密には間違っているそうですので、先に記述しておきます。RailsのMVC
MVCは次の3つの要素を指します。
- Model(モデル)
- View(ビュー)
- Controller(コントローラー)
それぞれの役割は次のようになります。
Model
データベースを管理し、検索・挿入・更新・削除などを行います。
View
Webページ上でどのように表示するかが定義されています。
Controller
ModelとViewに指示を出します。
Modelから必要な情報を取得し、それらをもとにViewにWebページを構築させます。また、RailsではControllerでの処理をアクションと呼び、
複数定義することができます。処理の流れ
Model・Controller・Viewは次の順番で処理されます。
もう少し具体的に処理を書きだすと
- 指定されたControllerの、指定されたアクションが起動
- ControllerはModelを通してデータベースとやりとりする
- データベースから取得したデータを元に、ControllerはViewにWebページを構築させる
- Viewの内容をレスポンスとして返す
といった流れとなります。
ルーティングについて
routes.rbファイルに定義された通り、
リクエストされたURLとControllerのアクションを結びつけます。
地図みたいなものですね。
おわりに
各ファイルの役割や処理の流れが整理できていなかったのですが、
投稿するためにまとめることで多少理解できたかなと思います。
コーディングしているときに迷わないよう、常に処理を意識しながら作業していこうと思います。
- 投稿日:2019-07-30T21:41:22+09:00
【初心者向け・動画付き】Railsで日時をフォーマットするときはstrftimeよりも、lメソッドを使おう
はじめに:日時の表示に関してよくある問題
何も考えずにViewに
created_at
のような日付を出力すると、「あれっ?」と思うような表示になることがあります。app/views/users/index.html.erb<% @users.each do |user| %> <tr> <td><%= user.name %></td> <!-- 作成日時を表示する --> <td><%= user.created_at %></td> <td><%= link_to 'Show', user %></td> <td><%= link_to 'Edit', edit_user_path(user) %></td> <td><%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %></td> </tr> <% end %>具体的には以下の2つのポイントが「あれっ?」と思う点だと思います。
- 日本時間(JST)ではなく、世界標準時(UTC)で表示されてしまう
- "Tue, 30 Jul 2019 00:12:19 +0000"のようなフォーマットは日本人にとって馴染みがない
この記事ではこの問題を解決する方法を紹介します。
タイムゾーンを日本時間に変更する
最初にタイムゾーンを日本時間にしましょう。
config/application.rb
に以下の設定を追加し、サーバーを再起動してください。config/application.rbmodule TimeFormatSandbox class Application < Rails::Application # ... # タイムゾーンを日本時間に設定 config.time_zone = 'Asia/Tokyo' end endこれで画面に表示された日時が日本時間になります。
日本人が読みやすい日時フォーマットにする
続いて、日時の表示形式を日本人が読みやすいフォーマットに変更しましょう。
strftimeでも変更できるが、あまりオススメできない
ネットを検索すると以下のように
strftime
メソッドを使って検索する方法がよく出てきます。<%= user.created_at.strftime('%Y/%m/%d %H:%M:%S') %>もちろんこれでも目的は達成できるのですが、他にも日時を表示するViewがあると、
'%Y/%m/%d %H:%M:%S'
のような書式文字列を繰り返し書かないといけないため、コードがDRYになりません。DRYでないコードは変更に弱いコードになります。
変更に弱いコードは良くないコードです。lメソッドでDRYに書式を指定する(オススメ)
Railsには
l
メソッドという便利なメソッドがあるので、これを活用しましょう。以下は
l
メソッドの使用例です。<!-- lメソッドを使って書式を指定する --> <td><%= l user.created_at %></td>ただし、
l
メソッドを使うだけでは何も変化がありません。
l
メソッドを活用するには、もう少し作業が必要です。次に行うのはロケールの設定です。
今回は日本人が読みやすい書式にするのが目的なので、アプリケーションのロケールを:ja
に設定します。
config/application.rb
に以下の設定を追加してください。config/application.rbmodule TimeFormatSandbox class Application < Rails::Application # ... # デフォルトのロケールを日本(ja)に設定 config.i18n.default_locale = :ja end end続いて、
config/locales/ja.yml
というファイルを作成し、以下のような設定を記述します。config/locales/ja.ymlja: time: formats: default: "%Y/%m/%d %H:%M:%S"上の設定は日時(time)のデフォルトの書式を
%Y/%m/%d %H:%M:%S
にするための設定です。これでサーバーを再起動すると、日本人向けの書式で日時が表示されます。
strftime
メソッドとは異なり、l foo.created_at
のような記述でどのViewでも同じ書式が得られるため、コードもDRYになります。Tips: i18n_generatorsでja.ymlを自動生成する
上で作成した
config/locales/ja.yml
は、i18n_generators gemを使って自動生成すると便利です。
このgemの使い方は以下のとおりです。まず、Gemfileにi18n_generatorsを追加し、
bundle install
を実行します。Gemfilegroup :development do # ... gem 'i18n_generators' end次にターミナルから以下のコマンドを実行します。
rails g i18n_locale ja
config/locales/ja.yml
が生成されるので、このファイルを開いてja > time > formats > default
の書式文字列を編集します。
デフォルトの書式文字列は"%Y年%m月%d日(%a) %H時%M分%S秒 %z"
になっているので、これを要件に合わせて変更してください。なお、i18n_generatorsが生成した
ja.yml
には他にも日本語ロケール向けの設定がたくさん定義されています。
i18n_generatorsに関する詳しい情報はREADMEを参照してください。https://github.com/amatsuda/i18n_generators
Tips: View以外ではI18n.lを使う
Viewでは
l
と書くだけでOKですが、l
メソッドがヘルパーメソッドとして提供されていない場所(Modelなど)では、l
だけではNoMethodErrorになります。
その場合は、l
の代わりにI18n.l
と書けば、日時をフォーマットすることができます。ちなみに
l
はlocalize
のエイリアスメソッドなので、localize
と書いても構いません。以下の記述はどれも同じ結果になります。
= l user.created_at = I18n.l user.created_at = localize user.created_at = I18n.localize user.created_at追記:Time::DATE_FORMATS[:default]を変更するのもオススメしない
日時のフォーマットを変更する方法としてもうひとつ、
Time::DATE_FORMATS[:default]
の設定を変えるという方法もあるようです。config/initializers/time_formats.rbTime::DATE_FORMATS[:default] = '%Y/%m/%d %H:%M:%S'こうすると、
l
メソッドもstrftime
も使わずに書式を統一することができます。<!-- 何もしなくても書式が'%Y/%m/%d %H:%M:%S'になる --> <td><%= user.created_at %></td>これだけ見ると「すごく便利じゃん!」と思うかもしれません。
ですが、アプリケーション全体のデフォルト設定が変わってしまうため、予期しない問題を引き起こすかもしれません。
実際に問題が発生する事例は以下の記事で紹介されています。RailsのTime::DATE_FORMATS[:default]は変更しないほうがいい - Qiita
ですので、この方法もあまりオススメできません。
動画はこちら
この記事の内容はYouTube動画としてアップしています。
動画を見たい方は以下のリンクから視聴してください。参考文献
- 投稿日:2019-07-30T20:23:52+09:00
rubyでスターリンソートをやってみた(ブロック渡しも可能)
今話題のスターリンソートを
ruby
で実装してみました。準備
stalin_sort.rbclass Array # Githubの実装と同様 def stalin_sort return [] if empty? max = first select do |x| next if max > x max = x x end end # ブロックあり def stalin_sort_by(&block) return [] if empty? max = yield(first) map { |x| [yield(x), x] } .select { |y, _x| next if max > y; max = y } .map { |_y, x| x } end endGithubの実装は
Array
を引数に取り実行していますが、ruby
の良さを活かすためクラス拡張に変更しました。実行
[1, 2, 1, 1, 4, 3, 9].stalin_sort # => [1, 2, 4, 9] names = %w(alice bob ava benjamin carol) # ブロックなし names.stalin_sort # => ["alice", "bob", "carol"] # ブロックあり names.stalin_sort_by(&:length) # => ["alice", "benjamin"]簡単になりますが以上です。
掲載したものより良いコードがあれば是非ともお願いします!引用元
- 投稿日:2019-07-30T19:57:27+09:00
cannot load such file -- bcrypt というエラー
passwordを暗号化したいために
gem bcryptをbundle installした後、
ブラウザを再起動したときに出たエラー原因はよくわからないですが、rails serverを再起動することで直りました。
定期的にrails serverは再起動した方がいいんですかねぇ、他にもこれを再起動することで直ったエラーがあったような参考URL↓
http://tusukuru.hatenablog.com/entry/2016/08/24/160059
- 投稿日:2019-07-30T15:10:49+09:00
printf("%02d", "08") でエラー
Rubyの
printf
には次のような仕様があることを知りました。printf("%02d", "07") # "07" printf("%02d", "08") # ArgumentError / invalid value for Integer(): "08"数値を表す書式(この例の
"d"
)があるときに、埋め込まれるものが文字列だった場合は、数値に変換されるというものです。"07"
は8進数の7です。"08"
は0で始まっているのに8進数の書式としておかしいのでエラーになります。C、Java、Pythonで試してみたところ、数値の書式に対応するものが文字列のときは必ずエラーになりました。PerlとPHPでは、数値の書式に対応する文字列は10進数として変換されます。
Rubyのソースコードでは、この仕様にあたる部分はsprintf.cの
rb_str_format
にありました(ver 2.5.2)。switch (*p) { (略) case 'd': (略) { volatile VALUE val = GETARG(); (略) switch (TYPE(val)) { (略) case T_STRING: val = rb_str_to_inum(val, 0, TRUE); goto bin_retry;
- 投稿日:2019-07-30T14:31:03+09:00
Raspberry Pi上でbundle installをして無理だった話
なぜRaspberry Piでrails?
家のPCがSurface Proなのだが、Surface ProはVirtual Boxが入らないので仮想環境でLinuxを動かせず、デュアルブートをするほどストレージに空き領域もないため仕方なくRaspberry Piで環境を構築したのである。
発生したエラー
Gemfileに「gem install bcrypt」を追加し、
>> bundle install
を実行したとき
Fetching bcrypt 3.1.13
Installing bcrypt 3.1.13 with native extensions
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.
・
・
・
・
An error occurred while installing bcrypt (3.1.13), and Bundler cannot continue.
Make sure that `gem install bcrypt -v '3.1.13' --source 'https://rubygems.org/'` succeeds before
bundling.
となった。
エラーメッセージの通りに
>> gem install bcrypt -v '3.1.13' --source 'https://rubygems.org/'
を実行する
すると、、、
Building native extensions. This could take a while...
ERROR: Error installing bcrypt:
ERROR: Failed to build gem native extension.
・
・
・
・
make "DESTDIR="
compiling bcrypt_ext.c
compiling crypt_blowfish.c
gcc -D__SKIP_GNU -I/home/pi/.rbenv/versions/2.5.3/include -D_FILE_OFFSET_BITS=64 -c -o x86.o x86.S
x86.S: Assembler messages:
x86.S:202: Error: junk at end of line, first unrecognized character is `,'
<builtin>: recipe for target 'x86.o' failed
make: *** [x86.o] Error 1
原因
エラーを見てわかる人もいるかと思うが、どうやらgem installで落としてくるパッケージにはrubyで書かれておらずx86用のCPUのマシンで動作するc言語で書かれたネイティブコードがあるらしい。
今回は「bcrypt」がそれに該当、、、さすがにこれをRaspberry PiのARM用にクロスコンパイルするパワーが無く断念
解決策
本来はRaspberry Piの上で開発などする人がいないかと思うが、、、同じような人がいたら
解決策としては
①自分でRaspberry PiのARM用にクロスコンパイルする
②別の環境でinstallする(他のx86が載っているPC環境かクラウド環境)組み込みエンジニアの見解としては断然②のほうが楽だと思われます笑
①でできた人がいたらそのファイルくださいね笑
- 投稿日:2019-07-30T11:07:06+09:00
Rails minitestでconcernsのテストを書く
はじめに
concerns
で実装はすっきりしたんだけど、minitest
でテストを書くときにどうするんだっけ?と困った。rspec
に入れ替えてshared_examples
使おうという声が聞こえるけどたぶん錯覚なんだ。実装サンプル
こんな感じのサンプルがありまして...
class SampleModel < ActiveRecord::Base include SampleConcern # name attribute defined endmodule SampleConcern extend ActiveSupport::Concern included do # concernsに実装するのはたぶん不適切だけど validate name, presence: true end def greet "I'm #{name}" end endテスト
SampleConcern
がActiveRecord
に依存しない(has_many
とかvalidates
が書いていない)場合はただのmodule
なので、テスト用クラスを作ってinclude
してやれば済む。
大人の事情により、依存しているクラスをテストする場合は以下のコードでテストが書ける。
(module
側のsetup
をincluded
の中に定義することでテストクラスのsuper
呼び出しを省略できるがケースバイケース)require 'test_helper' require 'models/sample_concern_test' class SampleModelTest < ActiveSupport::TestCase include SampleConcernTest def setup super end private def test_instance SampleModel.new end endmodule SampleConcernTest extend ActiveSupport::Concern def setup @my_sample = test_instance end included do test "correct name greeting" do name = "paty" @my_sample.name = name assert_equal "I'm #{name}", @my_sample.greet end end private def test_instance raise NotImplementedError.new("override with InheritanceClass.new") end end
- 投稿日:2019-07-30T07:47:53+09:00
【Rails】form_for 練習用に超簡単なミニアプリを作成する
はじめに
form_for系の練習のため、最小構成で登録系のアプリを作成。
後は個人で適当にカスタマイズ。仕様
- viewは情報登録画面(/view/user/new.html.erb)のみを定義。
- アカウント名、メールアドレス、パスワードのみをuserTBLに登録するフォームを設置。
- 情報登録後は情報登録画面(/view/user/new.html.erb)にリダイレクトさせる。
画面イメージ
ルーティングは以下のみ定義。
routes.rbRails.application.routes.draw do root 'users#new' resources :users, only: [:new, :create] enduserTBL
column 型 name string string password string 構築手順
アプリケーションをmysqlで作成
$ rails new rails_practice -d mysql -Tアプリケーションのディレクトリへ移動
$ cd rails_practiceDB作成
$ rake db:createusersコントローラ作成
$ rails g controller users以下の通り編集
users_controller.rbclass UsersController < ApplicationController class UsersController < ApplicationController def new @user = User.new end def create @user = User.new(user_params) @user.save redirect_to :root end private def user_params params.require(:user).permit(:name, :email, :password) end enduserモデル作成
$ rails g model userrails g model user コマンドで生成されたマイグレーションファイルを以下の通り編集
20190729115345_create_users.rbclass CreateUsers < ActiveRecord::Migration[5.2] def change create_table :users do |t| t.string :name t.string :email t.string :password t.timestamps end end endマイグレートコマンドを実行
$ rails db:migrateビュー作成
view/users/new.html.erb<head> <meta charset="utf-8"> </head> <h1> 会員登録 </h1> <body> <%= form_for(@user, url: users_path, method: :post) do |f| %> <p> <%= f.label :name, "アカウント名" %><br> <%= f.text_field :name %> </p> <p> <%= f.label :email, "メールアドレス" %><br> <%= f.email_field :email %> </p> <p> <%= f.label :password, "パスワード" %><br> <%= f.password_field :password %> </p> <%= f.submit "登録する"%> <% end %> </body>ルーティング設定
routes.rbRails.application.routes.draw do root 'users#new' resources :users, only: [:new, :create] end動作確認
入力
DBへの登録を確認
DBへの登録後、リダイレクト
以上
- 投稿日:2019-07-30T04:24:55+09:00
rails カラムの値 一斉変更
1日1回回答できるクイズの残回答数を24時にリセットするバッチにて用いた
app/models/quiz.rbclass Quiz < ActiveRecord::Base def self.reset_quota QuizUserStatus.all.update_all(quota: 1) end endなお、条件次第で残1以上になるため今回はこのような実装にした
以上。
- 投稿日:2019-07-30T04:07:45+09:00
ruby match 正規表現、大文字小文字区別しない
以下AndroidであればPlayStore、iosであればAppStoreにリダイレクトさせるロジックの一部
if ua.match(/android/i) != nil redirect_to "https://play.google.com/store/apps/details?id=hoge" elsif ua.match(/ios/i) != nil || ua.match(/iphone/i) != nil || ua.match(/ipad/i) != nil redirect_to "https://itunes.apple.com/th/app/fuga" end
- 投稿日:2019-07-30T00:50:46+09:00
Capistranoで、EC2+S3への自動デプロイで起きたエラー集と基礎用語
はじめに
メルカリクローンアプリの作成でグループ開発でデプロイを担当しました。
今回はほぼ前提知識ない中、疑問に思った用語とエラーの解決へのプロセス、そして今回意識した事を備忘録とチームメンバーとの共有資料として記載しておきます。環境
Ruby → 2.5.1
Rails → 5.2.3
Capistrano → 3.11.0
carrierwave用語
用語の説明ですが、100%正しい知識ではないかも知れないです。と言うのも、もっと深い知識を知るともっと差別化しないと状況がごちゃごちゃになると思いますが、今回は小規模での開発だったので最低限の知識で乗り切りました。
私は今後必要になったら、詳細について調べていくつもりです。もっと詳細に知りたい人は随時調べてみてください。●ssh
EC2に入るとき使っている下記のコマンド
$ ssh -i キーの名前.pem ec2-user@00.000.0.00Secure Shellの略。リモートコンピュータと通信するためのプロトコルです。
ざっくり鍵を使って暗号化と復号で認証作業をしています。
さらっとやったchomd600は読み込み、書き込み権限の付与をしています。●sudo
スーパーユーザーでdoする。スーパーユーザーとはrootの事です。
rootユーザーは権限が強過ぎるのでコマンド単位だけその力を使おうと言うコマンド。●mysqld
dはデーモンの略です。mysqldはmysqlからデータを持ってきたりしてくれるものと言う認識です。
デーモンは常に待機状態でいるプログラムです。●nginx
webサーバーの一つ。webサーバーとはリクエストを受け取り、レスポンスを返す役割を請け負っています。
nginxの特徴が気になる人は別途調べてみてください。●tail
logを見るときに使用。最後の10行が表示される。-fのオプションを使用する事でログを垂れ流しに出来る。
個人的には、あまり使いませんでした。●cat
ファイルの中身を見る事が出来る。logやエラーが起きた箇所の本番環境での記述を見るために使った。-nオプションで行数を表示出来るので見やすい.
●RAILS_ENV
動作環境を指定したい時に使用。環境がどうこうのエラーが出た時に確認したり、場合によっては環境を指定してあげないとエラーが出る事があったので使った。
エラーへの対処
まず最初に特に何もしていない部分のエラーが起きた時は、EC2インスタンスの停止→起動をするのが得策です。
無料枠を使っているせいなのか、期待通りの動きをしてくれない事があるらしいです。(真偽は確認していませんが、何日か空けて自動デプロイしようとすると大体エラーが出ていました。仕様と諦めていたので、わかる方教えてください)
なので、心辺りのないエラーや自動デプロイが止まる時は再起動をしてみて、それでも起こるならエラーに対処をしてくのが時間効率がいいと思います。
では、私がハマったり頻度の高かったエラーを書いていきます。Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
(2)の場合はsocketがないので
$ touch mysql.sockで、解決出来ると思います。ないなら作ってやる、それだけです。ここから発展して(38)に変わる事があるようですが、それは私は出会わなかったので、割愛します。
Can't connect to local MySQL server through socket '/tmp/mysql.sock' (111)
検索してみると、権限がない事に起因するエラーの様ですが、私の場合には当てはまりませんでした。mysqlにアクセス出来ない旨のエラーなのでひとまず
$ mysql -u root -pでひとまずルートに入る事が出来るが確認してみる→出来なかったら検索
入れたらsocketの指定をしているファイル(database.yml)の設定を見る
それも合っていたら、環境変数を指定してみる$ rake db:migrate RAILS_ENV=production私はこれで解決しました。
他にも、mysql.sockが消えていない為、新しいmysql.sockが生成出来ず起動できないみたいな事もある様です。
この辺の解決策は他の方の記事を参考に出来ると思うのでそちらを見てみてください。credentials.yml.enc
ここは一番苦労しました。ただ参考資料が沢山のあるので、状況を整理しながらやっていけば問題なく出来ると思います。
チーム開発で起こっていたミスとしては。
・master→rails newした人とデプロイ担当が違う為、master.keyが複数ある環境で開発を進めていた
・APIkeyを書く人が、自分のmaster.keyで新しいcredentials.ymlを作ってしまったファイルをmargeして本番環境で開けなくなった
などです。
暗号化されている為コンフリクトが起きた時にわかりにくいので、一度丁寧に確認するのが良いと思います。
今回のチーム開発では初期段階でmaster.keyの共有をして、使わないkeyは消してしまうのが得策と思います。以下、大変参考になった記事です。
https://qiita.com/NaokiIshimura/items/2a179f2ab910992c4d39
https://qiita.com/yuuuking/items/53a37a2e998972be32b8まとめ
チーム共有がメインの記事なので、分かりにくいところもあると思いますが、デプロイ担当で思ったことは、どの環境で、どのコマンドを、何に対してやったのかをわかった上で作業を進めるのが大切だと思いました(当たり前ですが)。
自分でも良くわからない状況で、適当にコマンドを叩いていると周りもフォローしにくくなりますし、泥沼にハマる確率が高くなります(体験談)。
頑張れ!デプロイ担当!
※口頭説明しながら前提で作ったのと、知識不足で憶測や間違った解釈を書いている可能性が高いので後日書き足すか、限定公開にする予定です。
- 投稿日:2019-07-30T00:07:55+09:00
VimmerがRuby on Railsを書くときに使えるプラグイン集 2019
vimでRuby on Railsを書くときに重宝するプラグインを紹介します。
- NERDTree ファイルツリー
- vim-rails ファイル移動、Railsコマンド実行
- fzf.vim インクリメンタル検索
- vim-endwise
if
やdef
などのend
補完- coc.nvim 補完
- ale 静的解析
- ruby-matchit
%
によるdef...end等のキーワードを移動設定例として、自分の
.vimrc
に書いている設定を載せてます。NERDTree
scrooloose/nerdtree
ファイルツリー機能が使えます。ド定番です。
参考
vim-plugin NERDTree で開発効率をアップする! @zwirkyvim-rails
tpope/vim-rails
railsプロジェクト内のシームレスな移動や、vimからのrailsコマンドの実行が出来るようになります。
GIFでは例として、
gf
でカーソル化の文字列から該当するファイルを開き、:A
で対応するspec
ファイルを開いています。参考
vim-rails よく使いそうなやつ @bibiofzf.vim
junegunn/fzf.vim
Go言語製の fzf と呼ばれるコマンドラインツールを使用したプラグインで、プロジェクト内のファイル名や、ソースコードの文字列あいまい検索ができます。
.vimrclet g:fzf_action = { \ 'ctrl-s': 'split' } nnoremap <C-p> :FZFFileList<CR> command! FZFFileList call fzf#run(fzf#wrap({ \ 'source': 'find . -type d -name .git -prune -o ! -name .DS_Store', \ 'down': '40%'})) nnoremap <C-b> :Buffers<CR> nnoremap <C-g> :Ag<CR> nnoremap <silent> <C-]> :call fzf#vim#tags(expand('<cword>'))<CR> let g:fzf_buffers_jump = 1 command! -bang -nargs=? -complete=dir Files \ call fzf#vim#files(<q-args>, fzf#vim#with_preview(), <bang>0)GIFでは
ctrl
+p
でファイル名検索、ctrl
+b
でバッファー検索をしています。
ctagsとの連携なんかもできちゃいます。
fzf.vim
はプラグイン本体に加えてfzf
そのもののインストールも必要になりますが、
fzf
はvim
抜きにしてもコマンドラインツールとしてとても優秀なのでオススメです。参考
fzfとvimで少ない労力で作業効率を引き上げた話 @Sa2Knight
さいつよのターミナル環境を構築しよう @b4b4r07ファイル検索プラグインの別の選択肢としてdenite.nvim(unite.vimのつよいやつ)というプラグインがあります。
もっと複雑な処理を走らせたい方におすすめです。(あんまりわかってない)vim-endwise
tpope/vim-endwise
def
...end
や、if
...end
などの対応するキーワードを自動補完してくれます。地味にきいてくる便利さです。
coc.nvim
neoclide/coc.nvim
coc.nvim
はTypeScript
製の補間プラグインです。LanguageServerProtocol(以下LSP)
と呼ばれる、コーディング支援用のプロトコルが使用可能で、強力な補完機能が使えます。
ruby
の場合、 solargraphと呼ばれるLSPのgem
を使用します。
coc.nvim
は、 独自の設定ファイルとして.vim/coc-settings.json
を使用します。coc-settings.json{ "suggest.enablePreselect": true, "solargraph.commandPath": "solargraphの絶対パス" }.vimrclet g:coc_global_extensions = ['coc-solargraph'] inoremap <silent><expr> <TAB> \ pumvisible() ? "\<C-n>" : \ <SID>check_back_space() ? "\<TAB>" : \ coc#refresh() inoremap <expr><S-TAB> pumvisible() ? "\<C-p>" : "\<C-h>" function! s:check_back_space() abort let col = col('.') - 1 return !col || getline('.')[col - 1] =~# '\s' endfunction右に[LS]と表記されている単語が、LSPによる補完候補です。
めっちゃ出ます。参考
LanguageServerProtocol(LSP)のススメ @himanoa
neovim + coc.nvim で LSP 藻ログ
coc.nvim
の他にも、asyncomplete + vim-lsp や、 deoplete + LanguageClient-neovim の組み合わせでもLSPの補完が使えます。ale
w0rp/ale
gem
のrubocop
構文エラーを自動で非同期静的解析してくれるツールです。.vimrclet g:ale_fixers = { \ 'ruby': ['rubocop'], \ }
if
...end
のend
を消すと構文エラーを指摘してくれます。言語ごとにfix, lintツールを指定すると
ruby
以外でも大活躍してくれます。参考
neovim + ?ale + ?rubocop hoshinotsuyoshi.comruby-matchit
vim-scripts/ruby-matchit
%を拡張して、def...end等のキーワードを移動出来るようになります。まとめ
他にも良いプラグインがあれば教えてください
それではよい vim, rails ライフを…
- 投稿日:2019-07-30T00:07:55+09:00
VimmerがRuby on Railsを書くときに使えるVimプラグイン集 2019
vimでRuby on Railsを書くときに重宝するプラグインを紹介します。
- NERDTree ファイルツリー
- vim-rails ファイル移動、Railsコマンド実行
- fzf.vim インクリメンタル検索
- vim-endwise
if
やdef
などのend
補完- coc.nvim 補完
- ale 静的解析
設定例として、自分の
.vimrc
に書いている設定を載せてます。NERDTree
scrooloose/nerdtree
ファイルツリー機能が使えます。ド定番です。
参考
vim-plugin NERDTree で開発効率をアップする! @zwirkyvim-rails
tpope/vim-rails
railsプロジェクト内のシームレスな移動や、vimからのrailsコマンドの実行が出来るようになります。
GIFでは例として、
gf
でカーソル下の文字列から該当するファイルを開き、:A
で対応するspec
ファイルを開いています。参考
vim-rails よく使いそうなやつ @bibiofzf.vim
junegunn/fzf.vim
Go言語製の fzf と呼ばれるコマンドラインツールを使用したプラグインで、プロジェクト内のファイル名や、ソースコードの文字列あいまい検索ができます。
.vimrclet g:fzf_action = { \ 'ctrl-s': 'split' } nnoremap <C-p> :FZFFileList<CR> command! FZFFileList call fzf#run(fzf#wrap({ \ 'source': 'find . -type d -name .git -prune -o ! -name .DS_Store', \ 'down': '40%'})) nnoremap <C-b> :Buffers<CR> nnoremap <C-g> :Ag<CR> nnoremap <silent> <C-]> :call fzf#vim#tags(expand('<cword>'))<CR> let g:fzf_buffers_jump = 1 command! -bang -nargs=? -complete=dir Files \ call fzf#vim#files(<q-args>, fzf#vim#with_preview(), <bang>0)GIFでは
ctrl
+p
でファイル名検索、ctrl
+b
でバッファー検索をしています。
ctagsとの連携なんかもできちゃいます。
fzf.vim
はプラグイン本体に加えてfzf
そのもののインストールも必要になりますが、
fzf
はvim
抜きにしてもコマンドラインツールとしてとても優秀なのでオススメです。参考
fzfとvimで少ない労力で作業効率を引き上げた話 @Sa2Knight
さいつよのターミナル環境を構築しよう @b4b4r07ファイル検索プラグインの別の選択肢としてdenite.nvim(unite.vimのつよいやつ)というプラグインがあります。
もっと複雑な処理を走らせたい方におすすめです。(あんまりわかってない)vim-endwise
tpope/vim-endwise
def
...end
や、if
...end
などの対応するキーワードを自動補完してくれます。地味にきいてくる便利さです。
coc.nvim
neoclide/coc.nvim
coc.nvim
はTypeScript
製の補間プラグインです。LanguageServerProtocol(以下LSP)
と呼ばれる、コーディング支援用のプロトコルが使用可能で、強力な補完機能が使えます。
ruby
の場合、 solargraphと呼ばれるLSPのgem
を使用します。
coc.nvim
は、 独自の設定ファイルとして.vim/coc-settings.json
を使用します。coc-settings.json{ "suggest.enablePreselect": true, "solargraph.commandPath": "solargraphの絶対パス" }.vimrclet g:coc_global_extensions = ['coc-solargraph'] inoremap <silent><expr> <TAB> \ pumvisible() ? "\<C-n>" : \ <SID>check_back_space() ? "\<TAB>" : \ coc#refresh() inoremap <expr><S-TAB> pumvisible() ? "\<C-p>" : "\<C-h>" function! s:check_back_space() abort let col = col('.') - 1 return !col || getline('.')[col - 1] =~# '\s' endfunction右に[LS]と表記されている単語が、LSPによる補完候補です。
めっちゃ出ます。参考
LanguageServerProtocol(LSP)のススメ @himanoa
neovim + coc.nvim で LSP 藻ログ
coc.nvim
の他にも、asyncomplete + vim-lsp や、 deoplete + LanguageClient-neovim の組み合わせでもLSPの補完が使えます。ale
w0rp/ale
gem
のrubocop
構文エラーを自動で非同期静的解析してくれるツールです。.vimrclet g:ale_fixers = { \ 'ruby': ['rubocop'], \ }
if
...end
のend
を消すと構文エラーを指摘してくれます。言語ごとにfix, lintツールを指定すると
ruby
以外でも大活躍してくれます。参考
neovim + ?ale + ?rubocop hoshinotsuyoshi.comまとめ
他にも良いプラグインがあれば教えてください
それではよい vim, rails ライフを…