- 投稿日:2020-04-06T23:48:40+09:00
【Rails】whenever によるバッチ処理(runner編)
はじめに
whenever が使いやすいと書かれていたにもかかわらず、少しはまってしまったのでまとめます。
特に、runner について書きたいと思います。GemFile
GemFile に whenever を追記して
bundle install
GemFilegem 'whenever', :require => false$ bundle install自動化したいソースを記述
と、その前に準備があります。
config/application.rb に 以下の1行を追記してください。
lib のディレクトリの内容を反映させるようです。ここがはまってしまったポイントです。
config/application.rbclass Application < Rails::Application # 追記 config.autoload_paths += Dir["#{config.root}/lib"] endlib/batch/hoge.rb に自動化したいソースを記述してください。
lib/batch/hoge.rbclass Batch::Hoge def self.hoge puts "Hoge!" end endターミナル上で実行できるかどうかを確認。
$ bundle exec rails runner Batch::Hoge.hoge => "Hoge!"自動化のスケジュールを作成
下記コマンドを実行することで、config/schedule.rb を作成。
$ bundle exec wheneverize .config/schedule.rb に、下記を記載。
自動化させたい頻度と実行したいメソッドを指定してください。config/schedule.rbset :output, 'log/crontab.log' set :environment, :development set :runner_command, "rails runner" every 1.day, at: '9:00 am' do runner "Batch::ManHoursToBacklog.send_backlog" end作成した自動化ソースをcronへ反映・確認・削除
# cron への反映 $ bundle exec whenever --update-crontab# cron へ反映した内容の確認(どちらの行でも確認できる) $ bundle exec whenever $ bundle exec crontab -e# cron へ反映した内容を削除 $ bundle exec whenever --clear-crontabまとめ
以上が whenever を使ったバッチ処理反映方法でした。
少しでも参考になる方がいれば嬉しいです。参考
- Railsで定期的にバッチ回す「Whenever」
- Rails runnerを使ってファイルを実行しました
- javan/whenever (GitHub)
- dignoe/whenever-elasticbeanstalk (GitHub)
- 投稿日:2020-04-06T23:04:39+09:00
[Ruby]fizzbuzz問題
fizzbuzz問題とは
数値が3の倍数であれば、戻り値は”Fizz”
数値が5の倍数であれば、戻り値は”Buzz”
数値が3の倍数であり5の倍数でもある場合は、戻り値は”FizzBuzz”
上記のどれも満たさない場合は、その数値自体を戻り値にする
というもの。転職活動時に簡単な問題として出題されるとなんどか見たので、復習がてら解いて見ました。rubyで解く
まず、メソッドを作ります。
def fizzbuzz(num) end次にif文で条件分岐させます。
def fizzbuzz(num) if num % 3 == 0 && num % 5 == 0 puts ”FizzBuzz” elsif num % 3 == 0 puts ”Fizz” elsif num % 5 == 0 puts ”Buzz” else puts num end end上から順に、
- numを3で割った余剰が0と等しい かつ numを5で割った余剰が0と等しい(num % 3 == 0 && num % 5 == 0)
- numを3で割った余剰が0と等しい(num % 3 == 0)
- numを5で割った余剰が0と等しい(num % 5 == 0)
- どれにも当てはまらない場合、numを出力
という風に条件分岐させました。
次は1から100まで繰り返してnumに代入させます。繰り返しなので、each文を使うことにします。(1..100).each do |num| def fizzbuzz(num) if num % 3 == 0 && num % 5 == 0 puts ”FizzBuzz” elsif num % 3 == 0 puts ”Fizz” elsif num % 5 == 0 puts ”Buzz” else puts num end end(1..100)とすることで、「1~100の範囲で」といった意味がつきます。そしてeachでそれをひとつずつ取り出して num に代入していきます。
最後にputs fizzbuzz(num)
を追加してあげれば完成です。num_max = 100 (1..num_max).each do |num| def fizzBuzz(num) if num % 3 == 0 && num % 5 == 0 puts "FizzBuzz" elsif num % 3 == 0 puts "Fizz" elsif num % 5 == 0 puts "Buzz" else puts num end end puts fizzBuzz(num) end
- 投稿日:2020-04-06T22:59:04+09:00
【Ruby】【短期】Qiitaの読んでおかなければいけない記事100選【毎日自動更新】
ページ容量を増やさないために、不具合報告やコメントは、説明記事 に記載いただけると助かります。
順位 記事名
________________________________________ユーザ 投稿日付
更新日付LGTM1 1 (下準備編)世界一丁寧なAWS解説。EC2を利用して、RailsアプリをAWSにあげるまで naoki_mochizuki 16/01/08
19/01/172591
1662 プログラミング勉強を加速させる7つの習慣 YudaiTsukamoto 16/12/15
16/12/212933
693 高校文化祭の食販で自動注文機を作った話 RyotaroSaito 19/11/15
19/12/221304
104 一番詳しいCSS設計規則BEMのマニュアル Takuan_Oishii 17/08/30
19/07/16787
1535 【初心者向け】丁寧すぎるRails『アソシエーション』チュートリアル【幾ら何でも】【完璧にわかる】? kazukimatsumoto 18/11/29
19/12/06711
1626 未経験からRuby on Railsを学んで仕事につなげるまでの1000時間メニュー saboyutaka 18/12/09
19/09/141178
557 【初心者向け】テストコードの方針を考える(何をテストすべきか?どんなテストを書くべきか?) jnchito 18/05/22
18/06/141173
758 使えるRSpec入門・その1「RSpecの基本的な構文や便利な機能を理解する」 jnchito 14/10/26
19/07/222924
09 【まつもとゆきひろ氏 特別講演】20代エンジニアのためのプログラマー勉強法のまとめ 2019/3/30 motoki4917 19/03/30
19/10/191642
3110 [Rails] deviseの使い方(rails5版) cigalecigales 16/11/13
18/05/17852
5911 非デザイナーエンジニアが一人でWebサービスを作るときに便利なツール32選 okappy 14/09/18
15/07/086312
012 Railsアプリケーションにおけるエラー処理(例外設計)の考え方 jnchito 15/09/28
20/02/031557
6813 Rails deviseで使えるようになるヘルパーメソッド一覧 tobita0000 17/05/07
17/05/07488
6214 Railsで超簡単API k-penguin-sato 18/06/27
20/02/24387
5915 Rails開発におけるwebサーバーとアプリケーションサーバーの違い(翻訳) jnchito 15/10/20
15/10/211223
3516 削除済(ID:b1aa2ae143624e551aea) saitoeku3 18/06/18
19/07/05299
5517 Rails5.2から追加された credentials.yml.enc のキホン NaokiIshimura 18/04/12
18/04/13413
4418 Rails における内部結合、外部結合まとめ yuyasat 16/09/03
19/01/14574
4519 プログラミング初心者歓迎!「エラーが出ました。どうすればいいですか?」から卒業するための基本と極意(解説動画付き) jnchito 16/06/26
19/05/011167
4220 なぜrailsの本番環境ではUnicorn,Nginxを使うのか? ~ Rack,Unicorn,Nginxの連携について ~【Ruby On Railsでwebサービス運営】 takahiro1127 18/05/13
19/11/13268
7421 「アプリケーションが壊れているのに検知できないテストコード」を書かないようにするための、べからず集 jnchito 20/01/29
20/02/09528
52822 (デプロイ編①)世界一丁寧なAWS解説。EC2を利用して、RailsアプリをAWSにあげるまで naoki_mochizuki 16/01/12
20/01/17569
5223 【これが無料?】無料で学べるプログラミング教材・ハンズオン一覧 kocpa 19/06/26
19/07/05935
924 【Rails 5】(新) form_with と (旧) form_tag, form_for の違い hmmrjn 18/07/01
18/07/03392
4225 rails generate migrationコマンドまとめ zaru 14/09/09
18/11/061467
026 Ruby on Rails, Vue.js で始めるモダン WEB アプリケーション入門 tatsurou313 19/02/11
19/09/29273
6527 [初心者向け] RubyやRailsでリファクタリングに使えそうなイディオムとか便利メソッドとか jnchito 13/11/04
18/03/143008
028 未経験者には全てが黒魔術に見える呪いがある mackey0022 19/10/15
19/10/18471
2229 「Railsは終わった」と言われる理由 klriutsa 19/03/05
19/08/22432
5530 【Rails 5.2】 Active Storageの使い方 hmmrjn 18/06/30
19/08/06338
4231 VSCodeでRuby On Railsを快適に書きたい sensuikan1973 18/10/07
19/06/17479
3632 【爆速成長!】プログラミング駆け出し〜オリジナルポートフォリオ作成までに参考にしたサイト一覧 taku99 20/03/27
20/03/27308
30833 【Rails】MySQL2がbundle installできない時の対応方法 fukuda_fu 19/03/21
19/04/10238
5834 【サーバーサイド一式】Docker + Rails + Circle CI + Terraformでインフラをコードで環境構築 & ECSへ自動コンテナデプロイ【前半】 kazukimatsumoto 19/12/04
19/12/16526
5335 Railsバリデーションまとめ shunhikita 15/02/24
17/11/151037
036 Rubyによるデザインパターンまとめ yuji_ariyasu 18/09/10
19/08/15525
3337 Ruby on Rails カラムの追加と削除 azusanakano 16/03/29
16/03/29310
4338 [Docker] 初心者が知っておくと便利かもしれない18の知識 enta0701 17/09/30
19/01/17376
2939 gem installでpermissionエラーになった時の対応方法 nishina555 18/11/25
19/09/25220
5340 スタブとモックの違い k5trismegistus 17/04/05
17/04/06361
3341 Ruby on Rails 6の主要な新機能・機能追加・変更点 ryohashimoto 18/12/22
19/10/21291
3842 【初心者向け】RailsのActive Recordの解説&メソッドまとめ ryokky59 18/10/05
18/10/05184
5043 bundle install と bundle updateの違いについて lasershow 16/01/21
16/01/21370
3044 決定版!!Haml小技まとめ!! yukimura1227 16/04/16
18/11/29293
3445 find、find_by、whereの違い tsuchinoko_run 18/03/17
18/03/17216
5046 mysql2 gemインストール時のトラブルシュート HrsUed 18/11/28
19/04/16264
2447 ActiveRecordのjoinsとpreloadとincludesとeager_loadの違い k0kubun 14/09/04
16/02/111507
048 Rubyの文字列とシンボルの違いをキッチリ説明できる人になりたい Kta-M 16/09/05
19/04/07441
2749 Railsアプリで Bootstrap 4 を利用する NaokiIshimura 17/11/03
19/08/14292
3350 bundle install時に--path vendor/bundleを付ける必要性は本当にあるのか、もう一度よく考えてみよう jnchito 19/06/06
19/06/07304
5051 Rails で includes して N+1 問題対策 hirotakasasaki 17/02/10
17/02/11321
3152 [Ruby入門] 14. 日付と時刻を扱う(全パターン網羅) prgseek 17/04/28
17/05/05289
3553 Capybaraチートシート morrr 17/08/19
17/08/19289
2454 RailsアプリをDockerで開発するための手順 togana 16/04/11
17/07/31684
2555 railsのrenderとredirect_toの違い 1ulce 16/12/02
16/12/02310
1956 【Rails初心者必見!】ひたすら丁寧にデータ取得を説明(find, where) mr-myself 15/09/03
15/09/03435
3757 [Rails]ransackを利用した色々な検索フォーム作成方法まとめ nishina555 17/03/02
19/05/13294
2958 (DB・サーバー構築編)世界一丁寧なAWS解説。EC2を利用して、RailsアプリをAWSにあげるまで naoki_mochizuki 16/01/10
19/01/17459
3359 bundle install 時、mysql2でエラー tktcorporation 18/12/26
19/07/25227
2860 【まつもとゆきひろ氏 特別講演】若手エンジニアの生存戦略に行ってきたので私的メモ DAdDY0055 18/06/23
18/06/271244
361 あなたはいくつ知っている?Rails I18nの便利機能大全! Kta-M 17/06/26
19/04/19350
2662 並行処理、並列処理のあれこれ Kohei909Otsuka 18/02/14
18/02/15215
3163 【Rails】deviseを導入してみる Hal_mai 18/11/07
18/11/08161
4264 rspec-rails 3.7の新機能!System Specを使ってみた jnchito 17/10/23
19/12/14362
2365 Awesome Ruby : 素晴しい Ruby のライブラリ・ツール・フレームワーク・ソフトウェアの数々 hatai 17/07/24
19/11/01550
1566 Railsのjbuilderの書き方と便利なイディオムやメソッド ryouzi 17/11/28
19/01/08274
2467 忘れがちなrenderメソッドの使い方まとめ [Rails] hayashino 18/11/24
18/12/01140
5468 Rails の session を完全に理解した zettaittenani 18/12/17
19/07/16184
3169 Bundlerの使い方 oshou 16/03/27
17/02/03387
2070 N+1問題 TsubasaTakagi 17/12/07
17/12/07188
3271 モデルやメソッドに名前を付けるときは英語の品詞に気をつけよう jnchito 14/05/28
17/06/273076
072 Ruby on Rails+ReactでCRUDを実装してみた yoshimo123 18/02/17
19/02/28240
2673 Railsのポリモーフィック関連とはなんなのか itkrt2y 16/12/03
18/12/20310
2874 【2018年版】macにrbenvを入れてrubyを管理できるようにしちゃう Alex_mht_code 18/04/17
19/06/07236
2175 RubyとRailsにおけるTime, Date, DateTime, TimeWithZoneの違い jnchito 14/12/07
18/01/251425
076 Rails 5.2 で ActiveSupport::MessageEncryptor::InvalidMessage scivola 18/05/24
19/05/27230
2877 Webpacker使うなら最低限これだけは知っておいてほしいこと chimame 18/08/07
19/12/18207
2878 使えるRSpec入門・その2「使用頻度の高いマッチャを使いこなす」 jnchito 14/11/05
19/07/22941
079 みんなRailsのSTIを誤解してないか!? yebihara 16/12/04
16/12/16429
2980 ニコニ立体を直した話 uproad3 19/11/07
19/12/02230
081 Docker + Rails + Puma + Nginx + MySQL eighty8 17/08/25
19/10/28174
3582 あなたはDRY原則を誤認している? yatmsu 16/12/06
18/07/29236
2583 使えるRSpec入門・その4「どんなブラウザ操作も自由自在!逆引きCapybara大辞典」 jnchito 15/01/01
19/07/221096
084 Ruby 正規表現の使い方 shizuma 15/07/27
15/07/28485
2585 VSCode公式の機能で、リモートサーバにSSHして編集する【Insiders Preview】 suzuki_sh 19/05/03
19/05/12372
1886 永久保存版!?伊藤さん式・Railsアプリのアップグレード手順 jnchito 19/08/18
19/10/24337
3787 はじめてのRails API c5meru 17/12/16
17/12/16296
1888 20万pv/月達成のwebサービスのRailsソースコード、全部見せます! kent_ear 18/07/31
19/08/22788
789 AWS:無料でSSL証明書を取得する方法 iwaseasahi 17/06/03
18/01/13255
2190 フロントエンド全然わからないマンが、ちょっとでも見た目のいいWebサービスを作ろうとしてやったこと liukoki 18/03/21
18/03/251018
1591 RubyのModuleの使い方とはいったい shiopon01 16/09/15
16/09/15264
2592 Rails enumについてまとめておく shizuma 16/01/07
16/01/07275
2393 redirect_to @userが何を省略しているかわかりますか?〜挫折しないRailsチュートリアル7章〜 Kawanji01 18/07/05
20/03/16168
4394 実務で学んだRailsの設計・リファクタリング wawoon 17/12/08
19/02/10203
2795 あなたがマスターしたのはいくつ? Railsを習得するために必要な技術要素の一覧 jnchito 16/07/06
16/07/261175
1796 railsで多対多のアソシエーションの作り方と、出来ること Kohei_Kishimoto0214 17/01/19
17/06/26286
1897 RailsアプリへのRspecとFactory_botの導入手順 Ushinji 18/01/08
19/12/14208
2398 [初学者]Railsのi18nによる日本語化対応 shimadama 18/07/31
20/03/22153
3599 docker-composeを爆速にする shotat 18/05/13
18/05/13174
46100 Railsのルーティングの種類と要点まとめ senou 16/05/20
19/02/05229
24
1行目が総数。2行目が直近3ヵ月。 ↩
- 投稿日:2020-04-06T22:58:54+09:00
【Ruby】【長期】Qiitaの読んでおかなければいけない記事100選【毎日自動更新】
ページ容量を増やさないために、不具合報告やコメントは、説明記事 に記載いただけると助かります。
順位 記事名
________________________________________ユーザ 投稿日付
更新日付LGTM1 1 (下準備編)世界一丁寧なAWS解説。EC2を利用して、RailsアプリをAWSにあげるまで naoki_mochizuki 16/01/08
19/01/172591
9132 プログラミング勉強を加速させる7つの習慣 YudaiTsukamoto 16/12/15
16/12/212933
4713 使えるRSpec入門・その1「RSpecの基本的な構文や便利な機能を理解する」 jnchito 14/10/26
19/07/222924
3434 非デザイナーエンジニアが一人でWebサービスを作るときに便利なツール32選 okappy 14/09/18
15/07/086312
3085 一番詳しいCSS設計規則BEMのマニュアル Takuan_Oishii 17/08/30
19/07/16787
5606 [初心者向け] RubyやRailsでリファクタリングに使えそうなイディオムとか便利メソッドとか jnchito 13/11/04
18/03/143008
1897 rails generate migrationコマンドまとめ zaru 14/09/09
18/11/061467
2168 【初心者向け】丁寧すぎるRails『アソシエーション』チュートリアル【幾ら何でも】【完璧にわかる】? kazukimatsumoto 18/11/29
19/12/06711
5119 [Rails] deviseの使い方(rails5版) cigalecigales 16/11/13
18/05/17852
25410 未経験からRuby on Railsを学んで仕事につなげるまでの1000時間メニュー saboyutaka 18/12/09
19/09/141178
48811 Railsアプリケーションにおけるエラー処理(例外設計)の考え方 jnchito 15/09/28
20/02/031557
24212 Rails開発におけるwebサーバーとアプリケーションサーバーの違い(翻訳) jnchito 15/10/20
15/10/211223
20313 【初心者向け】テストコードの方針を考える(何をテストすべきか?どんなテストを書くべきか?) jnchito 18/05/22
18/06/141173
31914 Railsバリデーションまとめ shunhikita 15/02/24
17/11/151037
19515 高校文化祭の食販で自動注文機を作った話 RyotaroSaito 19/11/15
19/12/221304
130416 【まつもとゆきひろ氏 特別講演】20代エンジニアのためのプログラマー勉強法のまとめ 2019/3/30 motoki4917 19/03/30
19/10/191642
46217 Rails deviseで使えるようになるヘルパーメソッド一覧 tobita0000 17/05/07
17/05/07488
27418 プログラミング初心者歓迎!「エラーが出ました。どうすればいいですか?」から卒業するための基本と極意(解説動画付き) jnchito 16/06/26
19/05/011167
21819 ActiveRecordのjoinsとpreloadとincludesとeager_loadの違い k0kubun 14/09/04
16/02/111507
14920 Rails における内部結合、外部結合まとめ yuyasat 16/09/03
19/01/14574
20421 (デプロイ編①)世界一丁寧なAWS解説。EC2を利用して、RailsアプリをAWSにあげるまで naoki_mochizuki 16/01/12
20/01/17569
20322 モデルやメソッドに名前を付けるときは英語の品詞に気をつけよう jnchito 14/05/28
17/06/273076
11923 Railsで超簡単API k-penguin-sato 18/06/27
20/02/24387
32424 RubyとRailsにおけるTime, Date, DateTime, TimeWithZoneの違い jnchito 14/12/07
18/01/251425
11825 使えるRSpec入門・その2「使用頻度の高いマッチャを使いこなす」 jnchito 14/11/05
19/07/22941
14026 使えるRSpec入門・その4「どんなブラウザ操作も自由自在!逆引きCapybara大辞典」 jnchito 15/01/01
19/07/221096
12727 Rails5.2から追加された credentials.yml.enc のキホン NaokiIshimura 18/04/12
18/04/13413
23628 脱初心者を目指すVimmerにオススメしたいVimプラグインや.vimrcの設定 jnchito 14/06/08
18/05/151938
8229 RailsアプリをDockerで開発するための手順 togana 16/04/11
17/07/31684
8830 Ruby on Rails カラムの追加と削除 azusanakano 16/03/29
16/03/29310
16331 【Rails 5】(新) form_with と (旧) form_tag, form_for の違い hmmrjn 18/07/01
18/07/03392
23932 bundle install と bundle updateの違いについて lasershow 16/01/21
16/01/21370
14333 スタブとモックの違い k5trismegistus 17/04/05
17/04/06361
16534 削除済(ID:b1aa2ae143624e551aea) saitoeku3 18/06/18
19/07/05299
26035 Rubyの文字列とシンボルの違いをキッチリ説明できる人になりたい Kta-M 16/09/05
19/04/07441
13636 【Rails初心者必見!】ひたすら丁寧にデータ取得を説明(find, where) mr-myself 15/09/03
15/09/03435
12137 【Rails 5.2】 Active Storageの使い方 hmmrjn 18/06/30
19/08/06338
21838 [Docker] 初心者が知っておくと便利かもしれない18の知識 enta0701 17/09/30
19/01/17376
19739 使えるRSpec入門・その3「ゼロからわかるモック(mock)を使ったテストの書き方」 jnchito 14/11/21
15/09/29969
10940 VSCodeでRuby On Railsを快適に書きたい sensuikan1973 18/10/07
19/06/17479
22541 なぜrailsの本番環境ではUnicorn,Nginxを使うのか? ~ Rack,Unicorn,Nginxの連携について ~【Ruby On Railsでwebサービス運営】 takahiro1127 18/05/13
19/11/13268
23442 決定版!!Haml小技まとめ!! yukimura1227 16/04/16
18/11/29293
15643 【これが無料?】無料で学べるプログラミング教材・ハンズオン一覧 kocpa 19/06/26
19/07/05935
93544 Rubyで%記法(パーセント記法)を使う mogulla3 14/08/23
14/08/23903
8645 Bundlerの使い方 oshou 16/03/27
17/02/03387
12146 「Railsは終わった」と言われる理由 klriutsa 19/03/05
19/08/22432
28047 railsのrenderとredirect_toの違い 1ulce 16/12/02
16/12/02310
15048 (DB・サーバー構築編)世界一丁寧なAWS解説。EC2を利用して、RailsアプリをAWSにあげるまで naoki_mochizuki 16/01/10
19/01/17459
13649 nil? empty? blank? present? の使い分け somewhatgood@github 13/01/24
13/01/241084
10050 Rails で includes して N+1 問題対策 hirotakasasaki 17/02/10
17/02/11321
12951 Ruby on Rails, Vue.js で始めるモダン WEB アプリケーション入門 tatsurou313 19/02/11
19/09/29273
26652 Awesome Ruby : 素晴しい Ruby のライブラリ・ツール・フレームワーク・ソフトウェアの数々 hatai 17/07/24
19/11/01550
11053 Rubyによるデザインパターンまとめ yuji_ariyasu 18/09/10
19/08/15525
17054 [Rails]ransackを利用した色々な検索フォーム作成方法まとめ nishina555 17/03/02
19/05/13294
14455 [Ruby入門] 14. 日付と時刻を扱う(全パターン網羅) prgseek 17/04/28
17/05/05289
14656 早く知ってたら良かったrailsの技 k-shogo 14/12/18
14/12/181125
7557 Ruby 正規表現の使い方 shizuma 15/07/27
15/07/28485
11758 Capybaraチートシート morrr 17/08/19
17/08/19289
14559 Railsアプリで Bootstrap 4 を利用する NaokiIshimura 17/11/03
19/08/14292
14660 あなたがマスターしたのはいくつ? Railsを習得するために必要な技術要素の一覧 jnchito 16/07/06
16/07/261175
9861 【Rails】form_for/form_tagの違い・使い分けをまとめた shunsuke227ono 15/04/28
16/11/15834
7162 Ruby block/proc/lambdaの使いどころ kidach1 13/11/18
17/01/291427
8363 あなたはいくつ知っている?Rails I18nの便利機能大全! Kta-M 17/06/26
19/04/19350
12764 知識0から、AWSのEC2でウェブサーバーを構築するまで shunsuke227ono 15/10/26
16/04/24461
9765 Railsのポリモーフィック関連とはなんなのか itkrt2y 16/12/03
18/12/20310
10466 中規模Web開発のためのMVC分割とレイヤアーキテクチャ yuku_t 14/05/20
17/08/151725
6767 みんなRailsのSTIを誤解してないか!? yebihara 16/12/04
16/12/16429
10168 【まつもとゆきひろ氏 特別講演】若手エンジニアの生存戦略に行ってきたので私的メモ DAdDY0055 18/06/23
18/06/271244
1069 Rails enumについてまとめておく shizuma 16/01/07
16/01/07275
10670 【初心者向け】これからRailsエンジニアとして成長したい人がすべきこと hc0208 16/03/21
18/10/15356
10371 Ruby on Rails 6の主要な新機能・機能追加・変更点 ryohashimoto 18/12/22
19/10/21291
21772 【Rails】MySQL2がbundle installできない時の対応方法 fukuda_fu 19/03/21
19/04/10238
23673 俺が悪かった。素直に間違いを認めるから、もうサービスクラスとか作るのは止めてくれ joker1007 16/12/15
17/01/08945
8474 RubyのModuleの使い方とはいったい shiopon01 16/09/15
16/09/15264
10775 rspec-rails 3.7の新機能!System Specを使ってみた jnchito 17/10/23
19/12/14362
13776 Railsのjbuilderの書き方と便利なイディオムやメソッド ryouzi 17/11/28
19/01/08274
13977 railsで多対多のアソシエーションの作り方と、出来ること Kohei_Kishimoto0214 17/01/19
17/06/26286
10378 gem installでpermissionエラーになった時の対応方法 nishina555 18/11/25
19/09/25220
20279 ノンプログラマーが3ヶ月でWebサービスを作ってみた tabbyz 15/02/25
16/03/271597
5680 あなたはDRY原則を誤認している? yatmsu 16/12/06
18/07/29236
11081 Railsのルーティングの種類と要点まとめ senou 16/05/20
19/02/05229
10382 mysql2 gemインストール時のトラブルシュート HrsUed 18/11/28
19/04/16264
21183 Ruby のエラーメッセージを読み解く(初心者向け)その 1 scivola 16/03/05
19/08/06256
10684 日本正式リリースしたStripeを使ってサブスクリプション型決済システムを実装する tady 16/10/04
18/05/21394
9285 find、find_by、whereの違い tsuchinoko_run 18/03/17
18/03/17216
14886 はじめてのRails API c5meru 17/12/16
17/12/16296
11687 フロントエンド全然わからないマンが、ちょっとでも見た目のいいWebサービスを作ろうとしてやったこと liukoki 18/03/21
18/03/251018
8388 YAMLとは何か? - いつもRailsの設定ファイルで出てくるやつの正体 Yama-to 15/07/27
15/08/08385
9689 20万pv/月達成のwebサービスのRailsソースコード、全部見せます! kent_ear 18/07/31
19/08/22788
6090 Rubyのメソッドの引数受け渡しまとめ raccy 16/07/17
19/12/25233
11291 (Capistrano編)世界一丁寧なAWS解説。EC2を利用して、RailsアプリをAWSにあげるまで naoki_mochizuki 16/02/01
19/11/14301
10092 Ruby on RailsのAjax処理のおさらい ka215 15/01/20
19/06/25728
7793 AWS:無料でSSL証明書を取得する方法 iwaseasahi 17/06/03
18/01/13255
11894 Rails 5 + ActionCableで作る!シンプルなチャットアプリ(DHH氏のデモ動画より) jnchito 15/12/22
16/07/13644
7895 今更聞けないpryの使い方と便利プラグイン集 k0kubun 14/12/21
16/01/16752
6096 並行処理、並列処理のあれこれ Kohei909Otsuka 18/02/14
18/02/15215
14197 正規表現のパフォーマンスの話をされても全くピンと来なかった僕は、backtrackに出会いました。 mochizukikotaro 16/05/28
17/04/04539
3598 最速!MacでRuby on Rails環境構築 narikei 15/12/12
19/03/05318
7799 Ruby on Rails+ReactでCRUDを実装してみた yoshimo123 18/02/17
19/02/28240
125100 【初心者向け】RailsのActive Recordの解説&メソッドまとめ ryokky59 18/10/05
18/10/05184
175
1行目が総数。2行目が直近1年。 ↩
- 投稿日:2020-04-06T22:34:41+09:00
Rubyで数値を3桁区切りにする方法 (正規表現)
背景
通貨を表示する際、数字を3桁区切りでカンマを挿入するかと思います。
Rails環境では
-number_to_currency
メソッド
-delimited
メソッド
どちらかを利用して簡単に表示できますが、Ruby環境では両者が利用できませんでした。そのため、正規表現を用いてメソッド化をしました。
number_to_currency
メソッドについては、Rubyで数値を3桁区切りにする方法!を参照してください。実装したコード
def converting_to_jpy(price) puts "#{price.to_s.reverse.gsub(/\d{3}/, '\0,').reverse}円" end converting_to_jpy(1234567890) # => 1,234,567,890円仕組み
考え方
数字の末尾から数えて3文字毎にカンマを入れる
つまり
1. 数字を文字列に変換
2. その文字列を反転(順番を入れ替える)
3. 3文字毎にカンマを入れる
4. 最後にもう一度反転させ、元の順番に戻すという流れで実装しました。
ポイントとしては、3. 3文字毎にカンマを入れる
の部分でしょうか。.gsub(pattern, replace)は文字列中で
pattern
にマッチする部分全てを文字列replace
で置き換えた文字列を生成して返すメソッドです。
また、\0
は一致した文字列全体に置換する正規表現です。このケースの場合\d{3}
に該当します。つまり、以下のように言えます。"1114447770".gsub(/\d{3}/, '\0,') # => "111,444,777,0" # 3文字毎の文字列の後ろにカンマを入れる開発環境
ruby 2.5.1
- 投稿日:2020-04-06T21:46:25+09:00
Kinx ライブラリ - Math
Math
はじめに
「見た目は JavaScript、頭脳(中身)は Ruby、(安定感は AC/DC)」 でお届けしているスクリプト言語 Kinx。言語はライブラリが命。ということでライブラリの使い方編。
今回は Math です。
- 参考
- 最初の動機 ... スクリプト言語 KINX(ご紹介)
- 個別記事へのリンクは全てここに集約してあります。
- リポジトリ ... https://github.com/Kray-G/kinx
- Pull Request 等お待ちしております。
Math は数値演算ライブラリ。同じメソッドが Integer、Double でも特殊メソッドとして使えるので、あえて Math オブジェクトを通して使う必要はない。例えば、以下のように使用できる。
var a = 2.pow(10); // Math.pow(2, 10) => 1024 var b = 2.0.pow(10); // Math.pow(2.0, 10) => 1024 var c = (-10).abs(); // Math.abs(-10) => 10単項マイナス(
-
)は関数呼び出しより優先順位が低いため、カッコで括る必要があることに注意。何気にrandom()
も数値に対して使えるが、レシーバーの値に意味はない、というのは知っていても良いし、まぁ知らなくても良い。var a = 1000.random(); // 1000 に意味はない var b = 10.0.random(); // 10.0 に意味はない var c = Math.random(); // Math には意味がある特殊メソッド、および特殊オブジェクトに関する詳細は Kinx ライブラリ - String を参照してください。
Math
Math オブジェクトのメソッド一覧は以下の通り。
メソッド 意味 Math.sin(dbl) サイン。 Math.sin(x)
は、$\sin x$ を求める。Math.cos(dbl) コサイン。 Math.cos(x)
は、$\cos x$ を求める。Math.tan(dbl) タンジェント。 Math.tan(x)
は、$\tan x$ を求める。Math.asin(dbl) アークサイン。 Math.asin(x)
は、$\sin θ=x$ となるような $θ$ を求める。Math.acos(dbl) アークコサイン。 Math.acos(x)
は、$\cos θ=x$ となるような $θ$ を求める。Math.atan(dbl) アークタンジェント。 Math.atan(x)
は、$\tan θ=x$ となるような $θ$ を求める。Math.atan2(dbl, dbl) アークタンジェント2。 Math.atan2(x,y)
は、$xy$ 直交座標における $(x,y)$ の偏角を求める。Math.sinh(dbl) ハイパボリックサイン。 Math.sinh(x)
は、$\sinh x$ を求める。Math.cosh(dbl) ハイパボリックコサイン。 Math.cosh(x)
は、$\cosh x$ を求める。Math.tanh(dbl) ハイパボリックタンジェント。 Math.tanh(x)
は、$\tanh x$ を求める。Math.exp(dbl) Math.exp(x)
は $e^x$ を返す。$e$ は、自然対数の底であるネイピア数(オイラー数)。Math.ldexp(dbl, int) Math.ldexp(x,y)
は $x \times 2^y$ を返す。Math.log(dbl) Math.log(x)
は $\log_e x$ を返す。Math.log10(dbl) Math.log10(x)
は $\log_{10} x$ を返す。Math.pow(dbl, dbl) Math.pow(x,y)
は $x^y$ を返す。Math.sqrt(dbl) Math.sqrt(x)
は $\sqrt x$ を返す。Math.ceil(dbl) Math.ceil(x)
は $x$ 以上の最小の整数値を Double で返す。Math.floor(dbl) Math.floor(x)
は $x$ 以下の最大の整数値を Double で返す。Math.fmod(dbl, dbl) Math.fmod(x,y)
は $x \div y$ の浮動小数点余剰を返す。結果は $x$ と同じ符号で $y$ 以下の絶対値となる。Math.abs(dbl) Math.abs(x)
は $x$ の絶対値を Double で返す。Math.random() Math.random()
は $0 \leq r < 1$ となる乱数を返す。おわりに
最初にも書いたが、同じメソッドが Integer、Double に直接作用するので、Math オブジェクト経由であえて使う必要はないかな、と。
ではまた次回。
- 投稿日:2020-04-06T19:47:58+09:00
1アクションで複数のビューを切り替えて表示しようとしたが、結局1アクション1ビューが良いという話
●はじめに
今回がQiita初投稿です。ポートフォリオを作成中に学んだ事をアウトプットする事を目的に始めました。
初歩的な内容が多いかと思いますが、是非、これからポートフォリオを作成する方に対し、役立てればという思いで発信しております。●概要
トップページに「投稿一覧」「いいねした投稿一覧」「自分の投稿一覧」というリンクを作成し、それぞれを1つのindexアクションにまとめようとようとした。しかしやはり基本的には1アクション1ビューが良いとのことでした。
●理由
・1つにまとめてしまうと、対応するURLがわかりにくくなる
・Railsの設計思想であるMVCの観点からやはり望ましい●実装方法
ちなみに、それでもあえて1つにまとめたいなら、パラメータを利用します。
if params[:name] == "post" @questions = Post.all elsif params[:name] == "like" 処理 elsif params[:name] == "user_post" 処理ですがおすすめとしてはアクションで分けてしまう事。
「例1」
・posts#index
・users#like_index
・users#post_indexリソースでまとめたいというこだわりがあるのであればコントローラーを作成する方法も。
「例2」
・posts#index
・users#show
・users::favorite#index●まとめ
Railsの場合は1アクション1ビューという基本を守った方が良い。
その場合、実装方法には様々な方法があるため、色々試して見るとより理解が深まるかもしれません。
- 投稿日:2020-04-06T19:12:08+09:00
Rails ウィザード形式導入について 3
はじめに
Rails ウィザード形式導入について 1 はこちらをクリック願います。
Rails ウィザード形式導入について 2 はこちらをクリック願います。
チーム開発でフリマサイトを開発致しました。
その際、ユーザーの新規登録画面でウィザード形式を導入致しましたので、内容を整理します。
もうすでにご存知の方、省略の仕方等ご存知でしたら、ご教授願います。前提
- ユーザー情報(User)については 以下 A と記述します。
- 住所情報(Destination)については 以下 B と記述します。
Bの登録の各アクション(create)とビュー(new,create)
ルーティング設定(new,create)
- B情報を登録するページを表示するnew_destinationアクションのルーティングを設定します。
- また、B情報を登録するcreate_destinationアクションのルーティングも設定します。
config/routes.rbRails.application.routes.draw do devise_for :users, controllers: {registrations: 'users/registrations'} #ここから↓ devise_scope :user do get 'destinations', to: 'users/registrations#new_destination' post 'destinations', to: 'users/registrations#create_destination' end #ここまで↑ root to: "top#index" endB情報のビューファイルの作成(new)
- 該当するビューファイルであるnew_destination.html.hamlを作成しまーす!
- 参考程度にみてください。このまま入力するとエラーが出るかも・・・です。
app/views/devise/registrations/new_address.html.haml.opi = form_for @destination do |f| .postal-code .postal-code__a .postal-code__a__a1 = f.label :post_code,"郵便番号" .postal-code__a__a2 必須 .postal-code__b = f.text_field :post_code,size:37, maxlength:7 .prefectures .prefectures__c .prefectures__c__c1 = f.label :prefecture_code_name,"都道府県" .prefectures__c__c2 必須 .prefectures__d = f.collection_select :prefecture_code, JpPrefecture::Prefecture.all, :name, :name, {prompt:'--'}, {class: "shipping__area-input-1"} .municipality .municipality__e .municipality__e__e1 = f.label :city,"市区町村" .municipality__e__e2 必須 .municipality__f = f.text_field :city,size:37 .address .address__g .address__g__g1 = f.label :house_number,"番地" .address__g__g2 必須 .address__h = f.text_field :house_number,size:37 .building .building__i .building__i__i1 = f.label :building,"建物名" .building__i__i2 任意 .building__j = f.text_field :building,size:37 .phone .phone__number1 .phone__number1__kk = f.label :phone_number,"電話番号" .phone__number1__yy 任意 .phone__number2 = f.text_field :phone_number,size:37,maxlength:11 .register %input#submit_button2{:name => "submit", :type => "submit", :value => "登録する"}/ここで一言!
- createアクション内で必要なインスタンス変数を定義してrenderしてます。
- なので、new_destinationアクションをコントローラ内に定義する必要はありませ-ん!
create_destinationアクションを定義する
app/controllers/users/registrations_controller.rbclass Users::RegistrationsController < Devise::RegistrationsController # 省略 def create_destination @user = User.new(session["devise.regist_data"]["user"]) @destination = Destination.new(destination_params) unless @destination.valid? flash.now[:alert] = @destination.errors.full_messages render :new_destination and return end @user.build_destination(@destination.attributes) @user.save sign_in(:user, @user) end protected def destination_params params.require(:destination).permit(:post_code, :prefecture_code, :city, :house_number, :building, :phone_number) end # 省略 end2ページ目で入力した住所情報のバリデーションチェック
- createアクションと同様に、valid?メソッドを用いて、バリデーションチェックを行います。
2ページ目の情報とSessionで保持していた情報とあわせ、ユーザー情報として保存
- build_destinationを用いて送られてきたparamsを、保持していたsessionが含まれる@userに代入します。
- saveメソッドを用いてテーブルに保存します。
ログインをすること
- 今のままだとユーザーの新規登録ができても、ログインができてません。
- sign_inメソッドを利用してログイン作業を行います。
最後にdestination_createに対応するビューを作成
- 該当するビューファイルであるcreate_destination.html.hamlを作成しまーす!
- 参考程度にみてください。このまま入力するとエラーが出るかも・・・です。
app/views/devise/registrations/create_destination.html.haml.main .done 会員登録完了 .mozi ありがとうございます。 会員登録が完了しました。 .login2 = link_to "トップへ戻る", root_path以上で完了です!できました?
個人で開発されるアプリにもぜひ導入してみてください!
UI性も増して、Looks Goodかと!さいごに
日々勉強中ですので、随時更新します。
皆様の復習にご活用頂けますと幸いです。
- 投稿日:2020-04-06T19:11:07+09:00
【Rails】GoogleBooksAPIを叩いて書籍検索機能作る【Ajax】
現在作成中のポートフォリオの最後の機能、
GooglebooksAPIを叩いて書籍検索をする機能がやっとできましたので、その奮闘記をここに記します。(ちなみにAWSデプロイエラー地獄にハマっている間に書いてます)
GoogleBooksAPIとは
Googleが提供している書籍情報のAPIです。
無料且つ簡単に利用できるので、書籍関連アプリを作る際に結構利用されてるみたいです。簡単に言うと、
https://www.googleapis.com/books/v1/volumes?q=おおきく振りかぶって&country=JP&maxResults=30
みたいな感じでキーワードを入れるとその情報がjson形式にされたファイルが表示されます。
これを利用すれば簡単に書籍情報をゲットできると言うわけですね〜。
便利。では早速取り掛かりましょう。
環境
- Ruby 2.6.3
- Rails 5.2.2
- Docker
- MacOS
前提
- 投稿機能はすでに作られている(post_controller)
最終目標
最終的にできて欲しいのは以下。
- 検索ボックスにキーワードを入力する
- キーワードに基いた検索結果が投稿フォームの下に表示される
そのために必要な処理
- 検索フォームにキーワードを入力
- キーワードをコントローラ側で受け取る
- 受け取ったキーワードを元にAPIを叩く
- 叩かれたAPIから情報を取得する
- 取得した情報を投稿画面に渡す
- 渡された情報でAjaxを発火させて投稿画面の部分テンプレートを更新する
大体前準備はこんな感じです。
以下からは具体的にコードの方を見ていきます。
検索フォームの設置
_search.html.erb<%= form_tag(new_post_path, method: :get, remote: true) do %> <input type="text" name="keyword" id="keyword" placeholder="書籍を検索"> <button type="submit"><i class="fas fa-search fa-lg"></i></button> <% end %>こちらのフォームではmethodをgetに設定しています。
理由は後ほど詳しく説明しますが、ざっくり言うと入力されたキーワードの送り先がpost_controllerのnewアクションだからです。また、remote:trueを設定しておくことでjsファイルを探してAjaxを発火させてくれます。
APIを叩くモジュールを作成
最初はコントローラーにAPIを叩く処理も書いていたのですが、かなりコードがごちゃごちゃしてしまったのとエラーが発生しやすかったので、別にモジュールを作って叩く処理はそこでまとめました。
app/lib/book.rbmodule BooksApi extend self def get_url(keyword) url = URI.encode("https://www.googleapis.com/books/v1/volumes?q=#{keyword}&country=JP&maxResults=30") response = HTTParty.get(url) end endget_urlは引数にkeywordが設定されており、画面から入力されたパラメータを受け取ってAPIの#{keyword}部分に渡されます。
HTTParty.get(url)でAPIを叩いて情報を取得します。
このHTTPartyは、自動でjsonを解析してrubyのhashに変換してくれる優れもの。#api関連 gem 'json' gem 'httparty'gemをインストールしときましょう。
コントローラーに取得した情報を渡す
検索フォームから受け取ったパラメーターを先ほど作成したモジュールを経由してAPIを叩き、コントローラーで取得します。
posts_controller.rbrequire 'net/http' require 'uri' require 'json' require 'httparty' class PostsController < ApplicationController #初期化 @results = [] def new if @results.present? @post = Post.new else @post = Post.new #url_from_keywordメソッドの呼び出し @results = url_from_keyword end end #パラメータを取得しkeywordに代入 def url_from_keyword keyword = params[:keyword] BooksApi.get_url(keyword) endまず一番上のrequire部分ですが、これはAPIを叩くために必要なものなのでちゃんと書いときましょう。
これがないとすぐエラーが出ます。では各アクションについて。
url_from_keywordアクション
posts_controller.rbdef url_from_keyword keyword = params[:keyword] BooksApi.get_url(keyword) endこれはパラメーターを受け取って、その情報を先ほど作成したモジュールに引数で渡してAPIの情報を取得する処理を行っています。
しかし、フォームから送信するパラメーターを直接ここに投げるわけではありません。
それが先ほどのmethod:getの話につながります。
newアクション
posts_controller.rbdef new if @results.present? @post = Post.new else @post = Post.new @results = url_from_keyword end endnewアクションではAPIの情報があるときとない時で処理を分けています。
ない時は@rersultsに初期値で空配列を入れており、処理はPost.newだけです。
APIが叩かれた場合はその情報を@resultsに入れてるので、Post.newと@resultsの情報の表示処理を行います。
先ほど検索フォームを作成した際、methodをgetに設定していたのはこのためです。
routes.rbresources :posts do post 'add' => 'likes#create' delete '/add' => 'likes#destroy' endnewアクションはresoucesでgetになっており、送られたパラメータの処理を行うのはnewアクション内ですので、methodもそれに合わせて設定していたわけですね。
検索結果一覧画面
では処理が完了したのでこの情報を表示させましょう。
一覧画面の部分テンプレート
_results.html.erb<div class="wrap" id="ajax-response"> <div class="container-fluid"> <div class="row"> <% for i in 0..29 do %> <div class="result-box"> <% if @results["items"][i]["volumeInfo"]["imageLinks"].nil? %> <img src="/images/noimage.png"> <% else %> <img src="<%= @results["items"][i]["volumeInfo"]["imageLinks"]["thumbnail"] %>" > <% end %> <% if @results["items"][i]["volumeInfo"]["title"].nil? %> <h3 class="title">情報がありません</h3> <% else %> <h3 class="title"><%= @results["items"][i]["volumeInfo"]["title"] %></h3> <% end %> <% if @results["items"][i]["volumeInfo"]["authors"].nil? %> <p class="author">情報がありません</p> <% else %> <p class="author"><%= @results["items"][i]["volumeInfo"]["authors"][0] %></p> <% end %> </div> <% end %> </div> </div> </div>正直これはあまり良い書き方ではないのですが…時間に追われていたというのもあってとりあえず表示を目指して書きました。
["items"][i]["volumeInfo"]["title"]みたいなのがいくつかあると思いますが、これは先に挙げたリンクのjsonです。
「itemsの中のi番目のvolumeInfoの中のtitle」といった感じで情報を表示しています。
表示したい数だけfor文で回したらいい感じに一覧画面ができました。
Ajax
app/views/posts/new.js.erb$('#render-results').html("<%= escape_javascript(render partial: "posts/results", locals: { results: @results }) %>");Ajaxは以前書いたいいね機能とほとんど同じです。
app/views/posts/new.html.erb<div class="container-fluid"> <div class="row"> <div class="center-block mx-auto"> <div id="search-box" class="center-block mx-auto"> <%= render 'posts/search' %> </div> <%= form_tag(posts_path,{method: :post}) do %> <%= render 'shared/post_form' %> <% end %> </div> <div id="render-results"> </div> </div> </div>投稿画面の下部にあるid="render-results"を取得して、そこに先ほどの検索結果一覧画面の部分テンプレートを挿入してる感じですね。
ここまでできたら上手くAjaxが発火して表示されてくれるはず。
ここでのハマりポイント
とか言いながら、この検索結果一覧表示画面には一つ問題があります。
それは、以下のようなエラーが出てしまうことです。undefined method [] for:NilClass意味としては「nilの時の[]が定義されてへんで」といった感じらしいので、
例えば「サムネイルの画像がない」みたいな一部の情報が欠けてる場合に発生してしまします。こいつの上手い対処法が分からず結構右往左往していました。
結局これも応急処置みたいな感じになってしまったのですが、
「定義されてへんのがアカンのやったら、定義したらええやん」
ということで、以下のように対処しました。app/lib/nil_class.rbclass NilClass def [](*) nil end endposts_controller.rbclass PostsController < ApplicationController @results = [] require 'nil_class' ...モジュールを作ったディレクトリにnilclass用のファイルを作り、それをrequireで呼び出してます。
これでとりあえず表示は問題ないです。
まとめ
今回このポートフォリオを作る中で結構ミソのとこではあったので、自分なりに色々がんばりました。
ぶっちゃけコードは美しくないのでそこはこれから改善したいと思います…。
ひとまず作品自体は大体完成したので、あとはデプロイだけです。
が、AWSのデプロイが全然できなくて絶賛躓き中でございます。
無事デプロイが完了しましたらその辺の奮闘記も書きたいと思いますので、その時はどうぞよろしくお願い致します。
ではでは。
- 投稿日:2020-04-06T17:17:52+09:00
rbenvでrubyのバージョンが切り替わらない件
概要
rbenvで rubyのバージョン管理をしていた。
新しくRubyをインストールし、バージョンを切り替えよう(2.5.1 -> 2.6.5)としたところ、
うまくいかなかったので、原因と解決法をメモしておきます。原因
ディレクトリごとのRubyバージョン指定を行っていた
下記のコマンドを実行していたため、「.ruby-version」ファイルが生成されていました。
rbenv local 2.5.1状況把握には下記のコマンドが有効です
$ rbenv versions system * 2.5.1 (set by /Users/~/.ruby-version) 2.6.52.5.1の隣に書いてあることを確認すると、
「/Users/~/.ruby-version」でRubyのバージョンを設定しているよ、とわかります。解決法1 「/Users/~/.ruby-version」ファイルの削除
Finder、ターミナルからファイルを削除すれば解決できます。
ただし、ファイル名の前に「.」がついているので、隠しファイルになっています。
そのため、Finder、ターミナルにデフォルトで表示されません。解決法2 ディレクトリごとのRubyバージョン指定を解除
下記のコマンドを実行し、ディレクトリごとのRubyバージョン指定を解除してあげれば解決
rbenv local --unset
- 投稿日:2020-04-06T16:59:03+09:00
While文の基本
環境,前提
Ruby 2.5.1
MacOS Mojave Ver.10.14.6本記事はRubyがインストールされた前提の記事です。
Rubyをインストールしたあと、とにかくRubyをいろいろ触ってみて慣れていくための記事です。お役に立てば幸いです。while文の基本
sample.rbwhile 条件 do // 繰り返す処理 endでは1から10までの合計をwhile文を用いて算出してみます。
sample.rbsum = 0 i = 0 while i <= 10 do sum += i i+=1 end puts sum実行結果は以下のように55となります。
Tarminal55while文とfor文の使い分け
どちらも繰り返し処理の際に用いられるものですが、どういった使い分けが良いでしょうか?以下のように使い分けるのが良いと思います。
・繰り返し回数が決まっておらず、条件を満たす限り回すのはwhile文
・回数が明確に決まっている場合はfor文
- 投稿日:2020-04-06T16:15:52+09:00
ブロックを使う配列のメソッド
mapメソッド
戻り値をそのまま新しい変数に入れることができる。
rubynumbers = [1,2,3,4,5] new_numbers = numbers.map { |n| n * 10 } puts new_numbers #=> [10,20,30,40,50]
selectメソッド
各要素を評価し、真の要素を戻り値として配列にして返すメソッド
rejectメソッドはselectの反対で真になった要素を除外した配列を返す。rubynumbers = [1,2,3,4,5] even_numbers = numbers.select { |n| n.even? } puts even_numbers #=> [2,4]
- 投稿日:2020-04-06T15:51:02+09:00
simple_formatで簡単にテキストの改行を実装(+CSSの適用、htmlエスケープも)
simple_formatの使い方
「railsでtext_areaの改行をviewへ反映させたい!」「改行して打ち込んだのになんか長い一文になっちゃう!」なんてことありますよね!
テキストの改行をviewへ反映する際はヘルパーメソッドのsimple_formatが有効です。使い方は至って簡単。
simple_format(任意のテキスト)
これだけで改行をviewへ反映させることが出来ます。例text = '…ああああ!! あああ……' <%= simple_format(text) %>出力…ああああ!! あああ……simple_formatなだけに非常にシンプルですね。
なんか<>で囲ったら出力されないんだけど…
そうなんですよ。困りましたね。
通常、railsではデフォルトでテキストがhtmlエスケープされています。
つまり例text = '<a href ="hoge://すごくわるいホームページ.コム">すごくわるいホームページ</a>' <%= text %>出力<a href ="hoge://すごくわるいホームページ.コム">すごくわるいホームページ</a>こうやってちゃんとhtmlタグをエスケープして出力してくれています。
これ、truncateメソッドとかも同じね!でもでも、実はこの
simple_format
メソッドは
表示させたい文字列を<p>
で囲ったり、改行は</br>
で置き換えたりすることで出力してくれています。
つまりそのままだとhtmlエスケープしてくれないんです。なので以下のように書いてしまうと…
例text1 = '<a href ="hoge://すごくわるいホームページ.コム">すごくわるいホームページ</a>' text2 = '<急募!> うちの犬の躾方法!' <%= simple_format(text1) %> <%= simple_format(text2) %>出力すごくわるいホームページ うちの犬の躾方法! # 悪いホームページへの直リンが貼られてしまう… # <急募!>がhtmlタグだと認識されてしまう…<急募!>が消えたどころか、すごく悪いホームページへのリンクも貼られてしまいます。
じゃあどうすんの!
textをhメソッドでhtmlエスケープしましょう!
h(text)
でテキストをhtmlエスケープできます。
htmlエスケープされたテキストをsimple_formatすれば解決です。例text1 = '<a href ="hoge://すごくわるいホームページ.コム">すごくわるいホームページ</a>' text2 = '<急募!> うちの犬の躾方法!' <%= simple_format(h(text1)) %> <%= simple_format(h(text2)) %>出力<a href ="hoge://すごくわるいホームページ.コム">すごくわるいホームページ</a> <急募!> うちの犬の躾方法!これで一件落着です。
classとかオプションも使えるの?
simple_format(h(text), class: 'hogehoge', style: 'color: red;')
こんな感じでclassやstyleのオプションも設定できます。
参考
https://railsdoc.com/view
https://qiita.com/mojihige/items/c01682774e8ef29b361f
(こっちのほうが詳しいとか言わない)
- 投稿日:2020-04-06T15:51:02+09:00
【Rails】simple_formatで簡単にテキストの改行を実装(+CSSの適用、htmlエスケープも)
simple_formatの使い方
「railsでtext_areaの改行をviewへ反映させたい!」「改行して打ち込んだのになんか長い一文になっちゃう!」なんてことありますよね!
テキストの改行をviewへ反映する際はヘルパーメソッドのsimple_formatが有効です。使い方は至って簡単。
simple_format(任意のテキスト)
これだけで改行をviewへ反映させることが出来ます。例text = '…ああああ!! あああ……' <%= simple_format(text) %>出力…ああああ!! あああ……simple_formatなだけに非常にシンプルですね。
なんか<>で囲ったら出力されないんだけど…
そうなんですよ。困りましたね。
通常、railsではデフォルトでテキストがhtmlエスケープされています。
つまり例text = '<a href ="hoge://すごくわるいホームページ.コム">すごくわるいホームページ</a>' <%= text %>出力<a href ="hoge://すごくわるいホームページ.コム">すごくわるいホームページ</a>こうやってちゃんとhtmlタグをエスケープして出力してくれています。
これ、truncateメソッドとかも同じね!でもでも、実はこの
simple_format
メソッドは
表示させたい文字列を<p>
で囲ったり、改行は</br>
で置き換えたりすることで出力してくれています。
つまりそのままだとhtmlエスケープしてくれないんです。なので以下のように書いてしまうと…
例text1 = '<a href ="hoge://すごくわるいホームページ.コム">すごくわるいホームページ</a>' text2 = '<急募!> うちの犬の躾方法!' <%= simple_format(text1) %> <%= simple_format(text2) %>出力すごくわるいホームページ うちの犬の躾方法! # 悪いホームページへの直リンが貼られてしまう… # <急募!>がhtmlタグだと認識されてしまう…<急募!>が消えたどころか、すごく悪いホームページへのリンクも貼られてしまいます。
じゃあどうすんの!
textをhメソッドでhtmlエスケープしましょう!
h(text)
でテキストをhtmlエスケープできます。
htmlエスケープされたテキストをsimple_formatすれば解決です。例text1 = '<a href ="hoge://すごくわるいホームページ.コム">すごくわるいホームページ</a>' text2 = '<急募!> うちの犬の躾方法!' <%= simple_format(h(text1)) %> <%= simple_format(h(text2)) %>出力<a href ="hoge://すごくわるいホームページ.コム">すごくわるいホームページ</a> <急募!> うちの犬の躾方法!これで一件落着です。
classとかオプションも使えるの?
simple_format(h(text), class: 'hogehoge', style: 'color: red;')
こんな感じでclassやstyleのオプションも設定できます。
参考
https://railsdoc.com/view
https://qiita.com/mojihige/items/c01682774e8ef29b361f
(こっちのほうが詳しいとか言わない)
- 投稿日:2020-04-06T15:25:32+09:00
ワンライナーへのリファクタリング
対象読者
プログラミング初学者
リファクタリングとは
外部から見た時の挙動は変えずに、プログラムの内部構造を整理すること
構造の階層化やプログラム内の要素につける名前を簡潔なものに書き換えるなどがあるリファクタリングのメリット
- コードの煩雑さ(性能劣化)が低減するため、トラブルを起りにくくなる
- コードを理解しやすくなり、引き継ぎ時の手間が減る
- 修正、追加をより早く、正確に行えるため、トラブル時の対応が速くなる
リファクタリングのデメリット
チーム開発の場合、メンバーが同じ修正方法の認識を持っていないと、各々が考える方法での修正となり、結局ソースコードを全体でみるとバラバラのままになる
本題:ワンライナーへのリファクタリング
以下のコードに関して、リファクタリングを行っていきます。
array = [1, 2, 3, 4, 5].map do |el| if el.odd? el end end.compact!前提知識
■ mapメソッド
オブジェクト.map { |変数| # 実行したい処理 }配列やハッシュオブジェクトの要素がひとつずつ順に配列内から取り出され、変数に要素が代入され、指定した変数名をブロック内で使用することができる。また、ブロック引数の値を新たな配列(= 既存の配列の書き換え(mutate)をしない)にして返す。
■ ブロック
do ~ end で囲まれた引数■ odd?メソッド
奇数かどうかをtrue or falseで判定するメソッド
偶数の場合は、even?メソッドがある2.odd? # => false 3.odd? # => true 2.even? # => true 3.even? # => false■ compact!メソッド
自身から破壊的に nil を取り除き、変更が行われた場合は self を、そうでなければ nil を返す
また、compact メソッドは自身から nil を取り除いた配列を生成して返す## arrayがnilを含んでいる時 array = [1,2,3,4,5,nil] # compact array.compact => [1, 2, 3, 4, 5] # compact! array.compact! => [1, 2, 3, 4, 5] ## arrayにnilがない時 array = [1,2,3,4,5] # compact array.compact => [1, 2, 3, 4, 5] # compact! array.compact! => nil以上を踏まえたリファクタリング結果
#1 array = [1, 2, 3, 4, 5].map { |el| el if el.odd? }.compact! #2 array = (1..5).to_a.delete_if { |el| el.even? } #3 array = (1..5).to_a.delete_if(&:even?) #4 array = [1, 2, 3, 4, 5].select{ |el| el.odd?}上記以外のメソッド
■ delete_ifメソッド
要素を順番にブロックに渡して評価し、その結果が真になった要素をすべて削除する
delete_if は常に self を返すarray = [0, 1, 2, 3, 4, 5] array.delete_if{|x| x % 2 == 0} p array #=> [1, 3, 5]■ to_aメソッド
ハッシュ、範囲オブジェクトなどを配列に変換するメソッド(1, 2, 3, 4, 5).to_a # => [1, 2, 3, 4, 5]mapメソッドを使用した場合は自動で配列を作成してくれていたので、to_aメソッドは不要でした
"a"はarray(配列)なので、"to_a"で"配列に(変換する)"メソッドですね
■ 範囲演算子
p (1..5).to_a # => [1, 2, 3, 4, 5] p (1...5).to_a # => [1, 2, 3, 4]■ array.method(&:method)
# array.method(&:メソッド名)の記法 ['a','b'].map(&:upcase) #=> ["A", "B"]■ selectメソッド
各要素に対してブロックを評価した値が真であった要素を全て含む配列を返す
真になる要素がひとつもなかった場合は空の配列を返す
ブロック({})を省略した場合は、各要素に対しブロックを評価し真になった値の配列を返すような Enumerator を返す[1,2,3,4,5].select # => #<Enumerator: [1, 2, 3, 4, 5]:select> [1,2,3,4,5].select { |num| num.even? } # => [2, 4]今回参考にさせていただいたサイト
- 投稿日:2020-04-06T13:18:17+09:00
apollo_upload_serverでActiveStorageにそのままファイルがアップロードできない
Rails + graphql-rubyでapollo_upload_serverを使ってファイルアップロード→activeStorageへ登録を試してみていて
ApolloUploadServer::Upload型の入力データを
modelにattachしてみたらエラーがでました入力データの定義
module Types class UserInputObject < Types::BaseInputObject argument :avatar, ApolloUploadServer::Upload, "user profile picture", required: false end endエラー内容
Could not find or build blob: expected attachable, got #<ActionDispatch::Http::UploadedFile:0x000055d4a2a41240これを解決するまでのメモです。
結論
こちらissueのコメントを参考に
ApolloUploadServer::Upload型を使うのをやめて、
自分でscalar型を宣言することで解決しました。
https://github.com/jetruby/apollo_upload_server-ruby/issues/10#issuecomment-394729475こんな感じです。
image_file.rbmodule Types class ImageFile < Types::BaseScalar description "upload file type" def self.coerce_input(file, context) file end end経緯
ActionDispatch::Http::UploadedFileではないのかと確認してみる
p input.avatar.class結果→
ApolloUploadServer::Wrappers::UploadedFile
調べてみるとActionDispatch::Http::UploadedFileのwrapperクラスであることがわかる↓
mutationのresolverで
ApolloUploadServer::Wrappers::UploadedFileから
ActionDispatch::Http::UploadedFileのインスタンスを取得できないかと考える↓
ソースを確認し、簡単には無理そうだなと理解
uploaded_file.rb# frozen_string_literal: true require 'delegate' require 'action_dispatch/http/upload' module ApolloUploadServer module Wrappers class UploadedFile < DelegateClass(::ActionDispatch::Http::UploadedFile) def initialize(wrapped_foo) super end def as_json(options = nil) instance_values.except('tempfile').as_json(options) end end end end↓
検索し、公式のissueでこの問題について議論しているページを発見
https://github.com/jetruby/apollo_upload_server-ruby/issues/10↓
いくつか解決方法が掲載されているけど
返却するとき(coerce_result)にも独自にscalar型を定義してactive_storageから
public_urlを取得する処理があったので
受け取る際の処理(coerce_input)に処理を書くかと結論の方法を採用もし他にいい方法があるよ!って場合はご教授いただけると
ありがたいです。
よろしくお願いします!
- 投稿日:2020-04-06T12:59:05+09:00
enum、scopeのロジック
enum
enumはint型、boolean型で定義されたカラムを、文字列で表現できるようにする機能です。
【例】class Drink < AppricationRecord # Drinkモデルのkindrカラムのenumを定義する # DBに保存されている値が0の時はtea, 1の時はcoffee、2の時はbeerを意味する enum kind: [:tea, :coffee, :beer] end【例】
@drink = Drink.new(kind: 1) @drink.kind # => 'coffee' # 数字ではなくenumで定義したキーワードが返ってくるenumを利用すると、数字と対応した文字列を返り値として出力できるようになります。
scope
scopeはモデルに対する絞り込みの条件に名前をつけて、メソッドのように呼び出し可能にする機能です。よく使う検索ロジックはscopeにしておくことによって、後から簡単に再利用できるようになります。
【例】今回はTaskモデルに「incoming」という名前でscopeを定義します。app/models/task.rbclass Task < ApplicationRecord enum kind: { individual: 0, work: 1, others: 2 } scope :incoming, -> { where('start_at > ?', Time.zone.now) } end定義したscopeを使って@tasksを再定義します。
app/controllers/tasks_controller.rbclass TasksController < ApplicationController def index @task = Task.new # モデルに定義したscopeはメソッドのように呼び出せる @tasks = Task.incoming.order(start_at: :asc) end # 以下省略参考リンク
enumリファレンス(英語)
enum_help Githubリポジトリ
Rails ModelのScope(スコープ)の使い方
- 投稿日:2020-04-06T12:24:55+09:00
素人がWebサービスを自分で作る備忘録(設計編)
はじめに
今回は前準備編の続きです。そちらに筆者のスキルレベルやこの記事の目的などが書いてありますので、先にお読みください。
Webサービスの設計
今回は前回の内容とほんのすこーしだけ重なる部分があるのですが、サービスの設計で何を行ったかを書いていきたいと思います。
まず、前回行ったWebサービスの企画の段階ではザックリどのような物を、何で、どんな機能を持たせるみたいなことを考えました。
そしてここから以下の設計を行っていきます。1.ワイヤーフレームを描く
2.それぞれのページのURLを考える
3.データベースの設計
4.ワイヤーフレームの見直し
5.やることの確認ワイヤーフレームとは
ワイヤーフレームっていうのはすごーく簡単に書いたページの全体像です。これを書くことによってサービスの全体像がイメージしやすくなり、作業する人たちのイメージのズレを少なくすることができます。(一人でやるんですが。。。)
今回は手書きでさっくりと作成しました。手順は
1.そのページに必要な情報を全て書き出す。(ピックアップ)
まずは何が必要なのか洗い出しましょう。ロゴとか登録フォームとか色々あると思うます。2.同じ性質のものをまとめる(グルーピング)
同じ性質のもの例えばメールアドレスとか電話番号とかは近くにおいといた方がユーザーが何か問い合わせたい時 に便利ですよね。なのでここで分けておきましょう。3.情報に優先順位を付ける(ランキング)
何を目立たせれば良いのか考えましょう。
例えばコーポレートサイトであれば会社名とか会社の概要とかですかね?今回は投稿機能がメインなのでログイン状態に関わらず投稿一覧画面は目立たせて見ます。ログイン後の画面では投稿フォームを目立たせるのもいいかなと思っています。4.レイアウトを考える
ここまで洗い出した情報をもとに簡単なレイアウトを作っていきます。
本当ならこの後にIllustratoやCacooなどのツールを使用して清書するのがいいのかもしれませんが今回はやりません。
ちなみにサイトを訪れる人は左上に最初に目が行きます。その為、目立たせたい情報は左上に配置するといいです。そして左上からそのまま左下へまたは、左上から右へといくことが多いです。これをF字パターンと言います。
こういったことから有名サービスのロゴは基本的に左上にあるんだと思います。URL決定
ワイヤーフレームが描けたらそれぞれのページのURLを考えていきましょう。(/loginとか/signupとか。。。)
まあ、初めてでそんなに複雑なアプリを作るわけではないので基本的にrailsチュートリアルで使ったようなURLでいきます。DB設計
Webサービスを作るのであればDBを使用することになりますが。その時に何のデータをどのテーブルに入れるのかということを考えていきます。
こんな感じ
・users
id:integer
name:string
email:stringこれも手書きd、、、
ワイヤーフレームの見直し
ここまでできたらワイヤーフレームで書いた内容がURLとDBで再現できるかを考えましょう。
SQLコマンドがイメージできるようにしておくと後が楽です。やることの確認
ここでいうやる事というのは、トップページの画面を作って、ログイン機能をつけて、ログアウト機能もつけてみたいなことです。ザックリページ単位でいいと思いますのでまとめておきましょう。
そして実装へ
ここまでやったらあとはガシガシ実装していくだけです。かなり大雑把に行ったので手戻り作業が多発することが予想されますがそういったところも今後の為にまとめていけたらいいなと思っております。
ここまで行ったこと
・基礎学習
・Webサービスの企画
なぜ作るのか
どのような物を作るのか
どういった機能が必要なのか
・Webサービス設計
ワイヤーフレーム作成
URL決定
画面遷移図の作成
データベース設計
タスクの確認参照元
初めての個人WEBサービスを作り始める前にやるべき設計
(https://www.muratayusuke.com/2016/01/16/how_to_design_web_app/)
- 投稿日:2020-04-06T12:12:36+09:00
MVCのリファクタリング
ビューのリファクタリング
ビューファイルで複雑な呼び出しを行っている場合
【例】
app/views/articles/index.html.erb<% Article.where(status: 1).order(likes_count: :desc).limit(10).each do |article| %> <%= article.title %> <% end %>この例では「表示処理を行う」ことを責務としたビュー上で、データの呼び出しに関する複雑な処理が書かれています。
このような複雑な処理は、「データ処理を行う」ことを責務としたモデルに記載します。なぜかというとビューファイルに複雑な記述があると、コードの視認性が悪くなります。また、モデルに記述すると、様々なアクションで用いることができます。
また、モデルに定義した処理を行った上で、コントローラでインスタンス変数として定義します。
modelclass Article < ActiveRecord::Base scope :popular, -> { order(likes_count: :desc) } enum status: { draft: 0, published: 1 } endcontroller
def index @articles = Article.published.popular.limit(10) endview
<% @articles.each do |article| %> <%= article.title %> <% end %>同じ処理を繰り返し記述している場合
app/views/books/show.html.erb<% if user_signed_in? %> <% if current_user == @book.user %> <%= link_to "編集", edit_book_path(@book) %> <% end %> <% end %>app/views/comments/show.html.erb<% if user_signed_in? %> <% if current_user == @comment.user %> <%= link_to "編集", edit_comment_path(@comment) %> <% end %> <% end %>上記の2つのコードでは「ユーザーがサインインしているか」「そのインスタンスに紐付いたユーザーがログインしているユーザーと一緒であるか」を判定する処理が共通しています。
この処理はアプリケーション内で使用頻度が高いものだと考えられるので、helperに処理を切り出してどのビューからでも呼び出せるようにします。app/helpers/application_helper.rbdef current_user_has?(instance) user_signed_in? && current_user == instance.user endapp/views/books/show.html.erb<% if current_user_has?(@book) %> <%= link_to "編集", edit_book_path(@book) %> <% end %>app/views/comments/show.html.erb<% if current_user_has?(@comment) %> <%= link_to "編集", edit_comment_path(@comment) %> <% end %>複雑な条件分岐がある場合
view
<% if @book.published? %> <% if @book.popular? %> <%= link_to "詳細", book_path(@book) ,class: "popular" %> <% else %> <%= link_to "詳細", book_path(@book) ,class: "normal" %> <% end %> <% else %> <div class=normal>閲覧不可</div> <% end %>ビューに複雑な条件分岐がある場合もhelperに処理を移動します。
helperではビューで使えるヘルパーメソッドが使用できます。
helperdef book_link(book) class_name = book.popular? ? "popular" : "normal" if book.published? content_tag :a, "詳細", class: class_name else content_tag :div, "閲覧不可", class: class_name end endview
<%= book_link(@book) %>複雑な条件分岐をhelperに移動することでビューの見通しが良くなります。
helper内は自由にコードを記述できるので、ビュー内で条件分岐をするよりもスッキリとわかりやすいコードにすることができます。同じビューを複数回記述してしまっている場合
app/views/books/show.html.erb<div class="book"> <span> <%= @book.title %></span> <p><%= @book.description %></p> <span><%= @book.author %></span> </div>app/views/books/index.html.erb<div class="book_list"> <% @books.each do |book| %> <div class="book"> <span> <%= book.title %></span> <p><%= book.description %></p> <span><%= book.author %></span> </div> <% end %> </div>繰り返し複数の箇所で使われるビューは部分テンプレートとして切り出して使用します。
app/views/books/_book.html.erb<div class="book"> <span> <%= book.title %></span> <p><%= book.description %></p> <span><%= book.author %></span> </div>app/views/books/show.html.erb<%= render partial: "book", locals: { book: @book } %>app/views/books/index.html.erb<div class="book_list"> <%= render @books %> </div>部分テンプレートとして切り出して使用する時の注意点は、「部分テンプレート内でインスタンス変数を使用しない」ことです。
部分テンプレート内では呼び出し元で定義されているインスタンス変数を使用することができます。しかし、これをしてしまうと呼び出し元のインスタンス変数の名前が異なる時に部分テンプレートを呼び出せなくなってしまいます。コントローラーのリファクタリング
複数のコントローラに同じ処理が記述されている場合(concerns)
開発の規模が大きくなるにつれ複数のコントローラに同じような処理が繰り返し記述されることがあります。この場合、
app/controllers/concernsにファイルを追加し、必要箇所で読み込ませます。
親コントローラにメソッドを定義する
などの方法でコントローラの記述を共通化することができます。
concerns ディレクトリに複数モデルで共通するコードをモジュールとして定義することでソースコードの見通しが改善できます。
【例】app/controllers/products_controller.rbclass ProductsController < ApplicationController before_action :set_cart ~省略~ private def set_cart @cart = Cart.find_by(id: session[:cart_id]) if @cart.nil? @cart = Cart.create session[:cart_id] = @cart.id end end endapp/controllers/top_controller.rbclass TopController < ApplicationController before_action :set_cart ~省略~ private def set_cart @cart = Cart.find_by(id: session[:cart_id]) if @cart.nil? @cart = Cart.create session[:cart_id] = @cart.id end end end上の2つのコントローラではどちらもset_cartというメソッドを定義して、インスタンス変数にカートのインスタンスを代入しています。
カート情報はこの2つのコントローラ以外でも頻繁に使用する可能性がありますが、そのたびにこのメソッドを追加していくのは好ましくありません。そこで以下のようにconcernsに処理を切り出してあげることで同じ処理を共通化できます。app/controllers/concerns/current_cart.rbmodule CurrentCart extend ActiveSupport::Concern private def set_cart @cart = Cart.find_by(id: session[:cart_id]) if @cart.nil? @cart = Cart.create session[:cart_id] = @cart.id end end endapp/controllers/products_controller.rbclass ProductsController < ApplicationController include CurrentCart before_action :set_cart endapp/controllers/top_controller.rbclass TopController < ApplicationController include CurrentCart before_action :set_cart endユーザーのカート情報を扱うためにそれぞれのコントローラでこのset_cartを定義する必要がありますが、定義したCurrentCartを使用したいコントローラで読み込むだけでそこに定義されているメソッドを使用することができるようになります。
複数のコントローラに同じ処理が記述されている場合(継承)
共通の処理を持つコントローラが同じ親コントローラを継承していれば、親コントローラに記述することで処理を共通化することができます。
app/controllers/sales_controller.rbclass SalesController < ApplicationController before_action :authorize_owner private def authorize_owner redirect_to root_path unless current_user.owner? end endapp/controllers/customers_controller.rbclass CustomersController < ApplicationController before_action :authorize_owner private def authorize_owner redirect_to root_path unless current_user.owner? end end例えば、上の2つのコントローラではauthorize_ownerを呼び出しています。この場合、SalesControllerとCustomersControllerはどちらもApplicationControllerを継承しているため、以下のように処理を共通化することができます。
app/controllers/application_controller.rbdef ApplicationController < ActionController::Base private def authorize_owner redirect_to root_path unless current_user.owner? end endapp/controllers/sales_controller.rbclass SalesController < ApplicationController before_action :authorize_owner endapp/controllers/customers_controller.rbclass CustomersController < ApplicationController before_action :authorize_owner end複数のアクションに同じ処理が記述されている場合
同じコントローラ内で同じような処理が繰り返し記述されている場合はcallbackを用いて共通化します。
controllerdef BookController < ApplicationController def index @books = Book.all end def show @book = Book.find(params[:id]) end def new @book = Book.new end def create Book.create(book_params) end def edit @book = Book.find(params[:id]) end def update @book = Book.find(params[:id]) @book.update(book_params) end def destroy @book = Book.find(params[:id]) @book.destroy end private ~省略~ end上のコントローラではshow, edit, update, destroyで共通して@book = Book.find(params[:id])という処理を行っています。
このような処理はbefore_actionなどのcallbackを利用して共通化します。
controllerdef BookController < ApplicationController bofore_action :set_book, only: [:show, :edit, :update, :destroy] def index @books = Book.all end def show end def new @book = Book.new end def create Book.create(book_params) end def edit end def update @book.update(book_params) end def destroy @book.destroy end private def set_book @book = Book.find(params[:id]) end ~省略~ endset_bookをbefore_actionで呼び出すことによってそれぞれのアクションで何をしているのかがよりわかりやすくなりました。
コントローラに複雑な処理を記述している場合
コントローラのコード量が多くなっている場合、本来モデルで行うべき処理がコントローラに書かれている可能性が高いです。このままでは、コントローラを変更する時に影響範囲が広くなってしまい、バグが発生する可能性が高まります。
この場合には、モデルのメソッドに処理を移動します。
before# controller @user = User.find(params[:user_id]) @user.name = params[:user_name] if params[company_name] @user.company_name = params[company_name] company = Company.find_by(name: params[company_name]) if company @user.company = company end end @user.saveafter
# controller @user = User.find(params[:user_id]) @user.update_company(params[company_name]) # model class User < ActiveRecord::Base def update_company(company_name) if company_name self.company_name = company_name company = Company.find_by(name: params[company_name]) if company self.company = company end end save end endこうすることで、他のアクションでもupdate_companyを呼び出せるようになり、アプリケーション全体で処理を統一することができます。
モデルのリファクタリング
ビューやコントローラから呼び出される様々な処理はモデルに集約されていくために、モデルは肥大化し易いです。そこで、モデルに書かれた処理を幾つかの観点で切り分けていくことでモデルの見通しを改善する方法を書いていきます。
Decorator(デコレーター)
【例】
app/models/user.rbclass User < ActiveRecord::Base def full_name "#{family_name} #{first_name}" end def full_name_kana "#{family_name_kana} #{first_name_kana}" end endDecorator(デコレーター)とはビューとモデルの中間に位置し、モデルやビューなどに実装されやすい表示ロジックやフォーマットなどの責務を引き受けるクラスです。
モデルにビューでしか使用しないメソッドが増えていくことがあります。上のfull_nameやfull_name_kanaと言ったメソッドがその例です。こうしたメソッドをデコレーターに移動することでコードの見通しが改善されます。
Railsでデコレーターを使用する場合にはdraperやactive_decoratorと言ったgemを使う方法が一般的です。今回はdraperを使った例を記述します。
active_decorator Github リポジトリ
「デコレーター」を導入するためのgemです。
【例】app/decorators/user_decorator.rbclass UserDecorator < Draper::Decorator delegate_all def full_name "#{family_name} #{first_name}" end def full_name_kana "#{family_name_kana} #{first_name_kana}" end endapp/controllers/users_controller.rbclass UsersController < ApplicationController def show @user = User.find(params[:id]).decorate end endapp/views/users/show.html.erb<%= @user.full_name %> <%= @user.full_name_kana %>Validator(バリデーター)
【例】
app/models/article.rbclass Article < ActiveRecord::Base validates :url, format: { with: /\A#{URI::regexp(%w(http https))}\z/ } endapp/models/products.rbclass Article < ActiveRecord::Base validates :url, format: { with: /\A#{URI::regexp(%w(http https))}\z/ } endモデルの役割の一つにバリデーションがあります。バリデーションとはデータの整合性を保つために、データを検証する機能のことです。
あるモデルのバリデーションに複雑な処理があったり、複数のモデルに共通のバリデーションが存在する場合にはそれらをモデルから切り離すことでリファクタリングが可能になります。
【例】app/models/articles.rbclass Article < ActiveRecord::Base validates :name, url_format: true endapp/models/products.rbclass Article < ActiveRecord::Base validates :url, url_format: true endapp/validators/url_format_validator.rbclass UrlFormatValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) if value.present? && value !~ /\A#{URI::regexp(%w(http https))}\z/ record.errors[attribute] << "のフォーマットが不正です" end end end上の例ではActiveModel::EachValidatorを継承したクラスの中にvalidate_eachというメソッドを定義しています。このクラスのファイル名から_validatorを取り除いたものを各クラスのvalidatesメソッドに引数として渡すと、そのカラムを検証する際にvalidate_eachメソッドが実行されます。
また、様々な属性値に対して複雑な検証を行う場合などには以下のような方法もあります。
【例】app/models/event.rbclass event < ActiveRecord::Base validates_with RangeValidator endapp/validators/range_validator.rbclass RangeValidator < ActiveModel::Validator def validate(record) unless start_time < finish_time record.errors.add :base, "finish_timeはstart_timeよりも後に設定してください。" end end endCallback(コールバック)
【例】
class BankAccount < ActiveRecord::Base before_save EncryptionWrapper.new after_save EncryptionWrapper.new after_initialize EncryptionWrapper.new end class EncryptionWrapper def before_save(record) record.credit_card_number = encrypt(record.credit_card_number) end def after_save(record) record.credit_card_number = decypt(record.credit_card_number) end def after_initialize(record) record.credit_card_number = decypt(record.credit_card_number) end private def encrypt(value) # 暗号化の処理 end def decrypt(value) # 解読の処理 end endコントローラ同様にモデルにもvalidationの直前に実行されるbefore_validationであったり、saveの直後に実行されるafter_saveなど様々なタイミングで実行されるコールバックが存在します。
開発が大規模になるとコールバックにたくさんのメソッドが登録され、メソッド同士の関係性がわかりづらくなっていくことがあります。
そのようなときには、callbackの引数に、そのコールバックと同名のメソッドを持つインスタンスを渡すことで、コールバックの処理を別のクラスに移動することができます。
この例ではbefore_saveでクレジットカードナンバーを暗号化し、after_initialize, after_saveで解読を行っています。このようにコールバック同士に関係性がある場合には別の一つのクラスとして扱うことによって関係性を明確にすることができます。
- 投稿日:2020-04-06T11:46:00+09:00
Rails_Twitter風いいね機能のエラーについて
Railsで開発中のTwitter風いいね機能のエラーについてで質問です。
Like、のボタンを押すと画像の様にエラーが出てしまいます。
原因については送信するidを受け取れないというよりはidを送っていない?と思うのですが色々やって見てもエラー祭りでどうなってるんだ。。。という状況です。
送信
https://i.gyazo.com/2ffbf11501a88d1ab5b1592b672ba33e.png
controller
https://i.gyazo.com/e5865d77d53d90f80f224fcfb3cab0da.png
エラー
https://i.gyazo.com/188748a8c789e4c870172d345c304466.png初心者のため稚拙な説明で申し訳ございません。
よろしくお願い致します。
- 投稿日:2020-04-06T02:29:53+09:00
Rubyのモジュールの参照順を実験した
確認したいこと
同名のモジュールが複数の名前空間に存在する時のincludeの参照順
実験
module TalkActions def say_my_name ###(1) puts "I am #{@name}[outside]" end end class Human module TalkActions def say_my_name ###(2) puts "I am #{@name}[inside]" end end include TalkActions ###(1),(2)のどちらをよみこむか? def initialize(name) @name = name end end John = Human.new("John") John.say_my_name ### I am John[inside] (2)だった
- 一応insideをコメントアウトして実行
module TalkActions def say_my_name ###(1) puts "I am #{@name}[outside]" end end class Human # module TalkActions # def say_my_name ###(2) # puts "I am #{@name}[inside]" # end # end include TalkActions ###ちゃんと(1)を読み込んでいることの確認 def initialize(name) @name = name end end John = Human.new("John") John.say_my_name ### I am John[outside] (1)が呼び出された結論
呼び出し元の名前空間から内→外へと探しにいくようだ。
- 投稿日:2020-04-06T02:29:53+09:00
Rubyのクラスがモジュールをinlcudeする時の参照順を実験してみた
確認したいこと
同名のモジュールが複数の名前空間に存在する時のincludeの参照順
実験
module TalkActions def say_my_name ###(1) puts "I am #{@name}[outside]" end end class Human module TalkActions def say_my_name ###(2) puts "I am #{@name}[inside]" end end include TalkActions ###(1),(2)のどちらをよみこむか? def initialize(name) @name = name end end John = Human.new("John") John.say_my_name ### I am John[inside] (2)だった
- 一応insideをコメントアウトして実行
module TalkActions def say_my_name ###(1) puts "I am #{@name}[outside]" end end class Human # module TalkActions # def say_my_name ###(2) # puts "I am #{@name}[inside]" # end # end include TalkActions ###ちゃんと(1)を読み込んでいることの確認 def initialize(name) @name = name end end John = Human.new("John") John.say_my_name ### I am John[outside] (1)が呼び出された結論
呼び出し元の名前空間から内→外へと探しにいくようだ。
- 投稿日:2020-04-06T02:15:06+09:00
Rubyのモジュールのインスタンスメソッドの挙動を実験してみた
確認したかったこと
モジュールのインスタンスメソッドからinclude元のクラスのインスタンス変数/メソッドを呼び出すことは可能か?
実験
module TalkActions def say_my_name puts "I am #{@name}" end def shout_my_name puts "I am #{self.name}!!!!!!!!" end end class Human attr_accessor :name include TalkActions def initialize(name) @name = name end end John = Human.new("John") John.say_my_name # 'I am John' John.shout_my_name # 'I am John!!!!!!!!'結論
どちらも呼び出し可能
- 投稿日:2020-04-06T02:00:34+09:00
Rubyのクラスにおける@とselfの整理
- 投稿日:2020-04-06T01:23:38+09:00
@keymoon氏の【全方位木DP】のRuby実装
【全方位木DP】明日使える便利な木構造のアルゴリズム
上記事の Ruby への単なる移植です。コード
Rubyclass ReRooting def initialize(identity, operate, &operate_node) @identity = identity @operate = ->(a, b) {[a, b].__send__(operate)} @operate_node = operate_node end def rerooting(node_count, edges) @node_count = node_count @adjacents = Array.new(@node_count) {[]} @index_for_adjacents = Array.new(@node_count) {[]} edges.each do |edge| @index_for_adjacents[edge[0]] << @adjacents[edge[1]].size @index_for_adjacents[edge[1]] << @adjacents[edge[0]].size @adjacents[edge[0]] << edge[1] @adjacents[edge[1]] << edge[0] end @dp = @adjacents.map {|ary| [ary.size]} @res = Array.new(@adjacents.size) case when @node_count > 1 init when @node_count == 1 @res[0] = @operate_node.(@identity, 0) end @res end def init parents = Array.new(@node_count) order = [] stack = [0] parents[0] = -1 until stack.empty? node = stack.pop order << node @adjacents[node].each do |adjacent| next if adjacent == parents[node] stack << adjacent parents[adjacent] = node end end #fromLeaf (order.size - 1).downto(1) do |i| node = order[i] parent = parents[node] accum = @identity parent_index = -1 @adjacents[node].each_index do |j| if @adjacents[node][j] == parent parent_index = j next end accum = @operate.(accum, @dp[node][j]) end @dp[parent][@index_for_adjacents[node][parent_index]] = @operate_node.(accum, node) end #toLeaf order.each do |node| accum = @identity accums_from_tail = Array.new(@adjacents[node].size) accums_from_tail[-1] = @identity (accums_from_tail.size - 1).downto(1) do |j| accums_from_tail[j - 1] = @operate.(@dp[node][j], accums_from_tail[j]) end accums_from_tail.each_index do |j| @dp[@adjacents[node][j]][@index_for_adjacents[node][j]] = @operate_node.(@operate.(accum, accums_from_tail[j]), node) accum = @operate.(accum, @dp[node][j]) end @res[node] = @operate_node.(accum, node) end end end例えばこんな感じで使います。
sample.rbedges = [[0, 1], [0, 4], [0, 6], [1, 2], [1, 3], [4, 5], [6, 10], [6, 11], [6, 7], [7, 8], [7, 9]] node_count = 12 res = ReRooting.new(0, :max) {|value, id| value + 1}.rerooting(node_count, edges) puts res.map(&:pred)おかしなところがあったら教えて下さい。
- 投稿日:2020-04-06T00:16:22+09:00
Kinx ライブラリ - String
String
はじめに
「見た目は JavaScript、頭脳(中身)は Ruby、(安定感は AC/DC)」 でお届けしているスクリプト言語 Kinx。言語はライブラリが命。ということでライブラリの使い方編。
今回は String です。
- 参考
- 最初の動機 ... スクリプト言語 KINX(ご紹介)
- 個別記事へのリンクは全てここに集約してあります。
- リポジトリ ... https://github.com/Kray-G/kinx
- Pull Request 等お待ちしております。
文字列操作の基本インターフェース。String オブジェクトに括り付いたメソッドは特殊メソッド(と呼ぶメソッドがある、名前は今決めた)扱いで、文字列オブジェクトに直接作用させることができる。
String 特殊オブジェクト
特殊メソッドを持つオブジェクトを特殊オブジェクトと呼び(←今決めた)、String、Array、Integer、Double、Binary がある。特殊メソッドは、特殊オブジェクトが対象としているオブジェクト(String なら文字列)に対して直接作用させることができる。
例えば、以下のように関数定義してみよう。
String.greeting = function(name) { System.println("Hello, I am %{name}."); };すると、以下のように書くことができるようになる。
"John".greeting();実行してみよう。
Hello, I am John.使い方によっては便利。ただし、ライブラリの追加(組み込み特殊メソッドの追加)で使う可能性がある ので乱用はあまりしないほうが良いかもしれない。
String
組み込み特殊メソッド
メソッド 意味 String.startsWith(str) 文字列が str
で始まれば true。String.endsWith(str) 文字列が str
で終れば true。String.find(str) 文字列の中で str
が見つかった位置(0~)を返す。見つからなかった場合は -1 を返す。String.subString(str, start[, len]) str
の部分文字列を返す。String.replace(str, cond, repl) str
からcond
にマッチする部分を全てrepl
に置換する。cond
は文字列または正規表現オブジェクトの指定が可能。String.toInt(str) str
を整数値に変換する。String.toDouble(str) str
を実数値に変換する。String.parentPath(str) str
をパスと認識し、親パスとなる部分文字列を返す。例)"ab/cd/ef.x".parentPath()
→"ab/cd.x"
String.filename(str) str
をパスと認識し、親パス部分を削除したファイル名部分文字列を返す。例)"ab/cd/ef.x".filename()
→"ef.x"
String.stem(str) str
をパスと認識し、ファイル名の stem 部分文字列を返す。例)"ab/cd/ef.x".stem()
→"ef"
String.extnsion(str) str
をパスと認識し、ファイル名の拡張子部分文字列を返す。例)"ab/cd/ef.x".extnsion()
→".x"
String.split(str, sep) str
をsep
を区切り文字として分割し、配列として返す。sep
は文字列、または正規表現オブジェクトの指定が可能。String.each(str, callback) str
を 1 文字ずつ分割し、それを引数にしてcallback
関数を呼び出す。callback
関数の第 2 引数に index (0~) も渡される。
each
は現在残念ながら日本語はうまく分割してくれないので注意。正式リリースまでに UTF-8 対応はさせる予定。特殊オペレーター
/
オペレーター文字列に対して
/
オペレーターを適用した場合、/
で連結した文字列を返す。その際、重複したセパレータは 1 つになる。var a = "aa/bb" / "ccdd"; // => "aa/bb/ccdd" var b = "aa/bb/" / "ccdd"; // => "aa/bb/ccdd" var c = "aa/bb" / "/ccdd"; // => "aa/bb/ccdd"
=~
オペレーター文字列に対して
=~
を適用した場合、右辺値には正規表現オブジェクトを期待する。正規表現のオブジェクトではなかった場合、例外が送出される。
!~
オペレーター文字列に対して
!~
を適用した場合、右辺値には正規表現オブジェクトを期待する。正規表現のオブジェクトではなかった場合、例外が送出される。後置
[]
オペレーター文字列に対してインデックスアクセスをした場合、その位置にある文字コードを整数値で返す。したがって、「5 文字目が
'a'
である」という判断をする場合は以下のように書く。if (str[5] == 'a'[5]) { /* ... */ }ちょっと C と違うことに注意。文字 'a' は文字ではなく 文字列リテラル のため、同じように
[5]
が必要。単項
*
オペレーター単項
*
オペレーターを文字列に適用した場合、文字列を配列に変換する。var a = *"abc"; // => [97, 98, 99]尚、補足として配列に単項
*
オペレーターを適用すると、文字列に戻ってくる。おわりに
文字列操作を簡単にしたいがためにスクリプト言語を使う、というのもよくあるシーン。そもそもコレ系スクリプトの元祖的な位置付けである Perl はテキスト処理が楽、ということで使われてた経緯もありますし。そういう意味で、文字列操作はプリミティブですが重要な機能。テキスト処理は C で書きたくない処理の一つですね。
ではまた次回。