20200406のRubyに関する記事は26件です。

【Rails】whenever によるバッチ処理(runner編)

はじめに

whenever が使いやすいと書かれていたにもかかわらず、少しはまってしまったのでまとめます。
特に、runner について書きたいと思います。

GemFile

GemFile に whenever を追記して bundle install

GemFile
gem 'whenever', :require => false
$ bundle install

自動化したいソースを記述

と、その前に準備があります。
config/application.rb に 以下の1行を追記してください。
lib のディレクトリの内容を反映させるようです。

ここがはまってしまったポイントです。

config/application.rb
class Application < Rails::Application
  # 追記
  config.autoload_paths += Dir["#{config.root}/lib"]
end

lib/batch/hoge.rb に自動化したいソースを記述してください。

lib/batch/hoge.rb
class 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.rb
set :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 を使ったバッチ処理反映方法でした。
少しでも参考になる方がいれば嬉しいです。

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[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
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby】【短期】Qiitaの読んでおかなければいけない記事100選【毎日自動更新】

ページ容量を増やさないために、不具合報告やコメントは、説明記事 に記載いただけると助かります。

順位 記事名
________________________________________
ユーザ 投稿日付
更新日付
LGTM1
1 (下準備編)世界一丁寧なAWS解説。EC2を利用して、RailsアプリをAWSにあげるまで naoki_mochizuki 16/01/08
19/01/17
2591
166
2 プログラミング勉強を加速させる7つの習慣 YudaiTsukamoto 16/12/15
16/12/21
2933
69
3 高校文化祭の食販で自動注文機を作った話 RyotaroSaito 19/11/15
19/12/22
1304
10
4 一番詳しいCSS設計規則BEMのマニュアル Takuan_Oishii 17/08/30
19/07/16
787
153
5 【初心者向け】丁寧すぎるRails『アソシエーション』チュートリアル【幾ら何でも】【完璧にわかる】? kazukimatsumoto 18/11/29
19/12/06
711
162
6 未経験からRuby on Railsを学んで仕事につなげるまでの1000時間メニュー saboyutaka 18/12/09
19/09/14
1178
55
7 【初心者向け】テストコードの方針を考える(何をテストすべきか?どんなテストを書くべきか?) jnchito 18/05/22
18/06/14
1173
75
8 使えるRSpec入門・その1「RSpecの基本的な構文や便利な機能を理解する」 jnchito 14/10/26
19/07/22
2924
0
9 【まつもとゆきひろ氏 特別講演】20代エンジニアのためのプログラマー勉強法のまとめ 2019/3/30 motoki4917 19/03/30
19/10/19
1642
31
10 [Rails] deviseの使い方(rails5版) cigalecigales 16/11/13
18/05/17
852
59
11 非デザイナーエンジニアが一人でWebサービスを作るときに便利なツール32選 okappy 14/09/18
15/07/08
6312
0
12 Railsアプリケーションにおけるエラー処理(例外設計)の考え方 jnchito 15/09/28
20/02/03
1557
68
13 Rails deviseで使えるようになるヘルパーメソッド一覧 tobita0000 17/05/07
17/05/07
488
62
14 Railsで超簡単API k-penguin-sato 18/06/27
20/02/24
387
59
15 Rails開発におけるwebサーバーとアプリケーションサーバーの違い(翻訳) jnchito 15/10/20
15/10/21
1223
35
16 削除済(ID:b1aa2ae143624e551aea) saitoeku3 18/06/18
19/07/05
299
55
17 Rails5.2から追加された credentials.yml.enc のキホン NaokiIshimura 18/04/12
18/04/13
413
44
18 Rails における内部結合、外部結合まとめ yuyasat 16/09/03
19/01/14
574
45
19 プログラミング初心者歓迎!「エラーが出ました。どうすればいいですか?」から卒業するための基本と極意(解説動画付き) jnchito 16/06/26
19/05/01
1167
42
20 なぜrailsの本番環境ではUnicorn,Nginxを使うのか?  ~ Rack,Unicorn,Nginxの連携について ~【Ruby On Railsでwebサービス運営】 takahiro1127 18/05/13
19/11/13
268
74
21 「アプリケーションが壊れているのに検知できないテストコード」を書かないようにするための、べからず集 jnchito 20/01/29
20/02/09
528
528
22 (デプロイ編①)世界一丁寧なAWS解説。EC2を利用して、RailsアプリをAWSにあげるまで naoki_mochizuki 16/01/12
20/01/17
569
52
23 【これが無料?】無料で学べるプログラミング教材・ハンズオン一覧 kocpa 19/06/26
19/07/05
935
9
24 【Rails 5】(新) form_with と (旧) form_tag, form_for の違い hmmrjn 18/07/01
18/07/03
392
42
25 rails generate migrationコマンドまとめ zaru 14/09/09
18/11/06
1467
0
26 Ruby on Rails, Vue.js で始めるモダン WEB アプリケーション入門 tatsurou313 19/02/11
19/09/29
273
65
27 [初心者向け] RubyやRailsでリファクタリングに使えそうなイディオムとか便利メソッドとか jnchito 13/11/04
18/03/14
3008
0
28 未経験者には全てが黒魔術に見える呪いがある mackey0022 19/10/15
19/10/18
471
22
29 「Railsは終わった」と言われる理由 klriutsa 19/03/05
19/08/22
432
55
30 【Rails 5.2】 Active Storageの使い方 hmmrjn 18/06/30
19/08/06
338
42
31 VSCodeでRuby On Railsを快適に書きたい sensuikan1973 18/10/07
19/06/17
479
36
32 【爆速成長!】プログラミング駆け出し〜オリジナルポートフォリオ作成までに参考にしたサイト一覧 taku99 20/03/27
20/03/27
308
308
33 【Rails】MySQL2がbundle installできない時の対応方法 fukuda_fu 19/03/21
19/04/10
238
58
34 【サーバーサイド一式】Docker + Rails + Circle CI + Terraformでインフラをコードで環境構築 & ECSへ自動コンテナデプロイ【前半】 kazukimatsumoto 19/12/04
19/12/16
526
53
35 Railsバリデーションまとめ shunhikita 15/02/24
17/11/15
1037
0
36 Rubyによるデザインパターンまとめ yuji_ariyasu 18/09/10
19/08/15
525
33
37 Ruby on Rails カラムの追加と削除 azusanakano 16/03/29
16/03/29
310
43
38 [Docker] 初心者が知っておくと便利かもしれない18の知識 enta0701 17/09/30
19/01/17
376
29
39 gem installでpermissionエラーになった時の対応方法 nishina555 18/11/25
19/09/25
220
53
40 スタブとモックの違い k5trismegistus 17/04/05
17/04/06
361
33
41 Ruby on Rails 6の主要な新機能・機能追加・変更点 ryohashimoto 18/12/22
19/10/21
291
38
42 【初心者向け】RailsのActive Recordの解説&メソッドまとめ ryokky59 18/10/05
18/10/05
184
50
43 bundle install と bundle updateの違いについて lasershow 16/01/21
16/01/21
370
30
44 決定版!!Haml小技まとめ!! yukimura1227 16/04/16
18/11/29
293
34
45 find、find_by、whereの違い tsuchinoko_run 18/03/17
18/03/17
216
50
46 mysql2 gemインストール時のトラブルシュート HrsUed 18/11/28
19/04/16
264
24
47 ActiveRecordのjoinsとpreloadとincludesとeager_loadの違い k0kubun 14/09/04
16/02/11
1507
0
48 Rubyの文字列とシンボルの違いをキッチリ説明できる人になりたい Kta-M 16/09/05
19/04/07
441
27
49 Railsアプリで Bootstrap 4 を利用する NaokiIshimura 17/11/03
19/08/14
292
33
50 bundle install時に--path vendor/bundleを付ける必要性は本当にあるのか、もう一度よく考えてみよう jnchito 19/06/06
19/06/07
304
50
51 Rails で includes して N+1 問題対策 hirotakasasaki 17/02/10
17/02/11
321
31
52 [Ruby入門] 14. 日付と時刻を扱う(全パターン網羅) prgseek 17/04/28
17/05/05
289
35
53 Capybaraチートシート morrr 17/08/19
17/08/19
289
24
54 RailsアプリをDockerで開発するための手順 togana 16/04/11
17/07/31
684
25
55 railsのrenderとredirect_toの違い 1ulce 16/12/02
16/12/02
310
19
56 【Rails初心者必見!】ひたすら丁寧にデータ取得を説明(find, where) mr-myself 15/09/03
15/09/03
435
37
57 [Rails]ransackを利用した色々な検索フォーム作成方法まとめ nishina555 17/03/02
19/05/13
294
29
58 (DB・サーバー構築編)世界一丁寧なAWS解説。EC2を利用して、RailsアプリをAWSにあげるまで naoki_mochizuki 16/01/10
19/01/17
459
33
59 bundle install 時、mysql2でエラー tktcorporation 18/12/26
19/07/25
227
28
60 【まつもとゆきひろ氏 特別講演】若手エンジニアの生存戦略に行ってきたので私的メモ DAdDY0055 18/06/23
18/06/27
1244
3
61 あなたはいくつ知っている?Rails I18nの便利機能大全! Kta-M 17/06/26
19/04/19
350
26
62 並行処理、並列処理のあれこれ Kohei909Otsuka 18/02/14
18/02/15
215
31
63 【Rails】deviseを導入してみる Hal_mai 18/11/07
18/11/08
161
42
64 rspec-rails 3.7の新機能!System Specを使ってみた jnchito 17/10/23
19/12/14
362
23
65 Awesome Ruby : 素晴しい Ruby のライブラリ・ツール・フレームワーク・ソフトウェアの数々 hatai 17/07/24
19/11/01
550
15
66 Railsのjbuilderの書き方と便利なイディオムやメソッド ryouzi 17/11/28
19/01/08
274
24
67 忘れがちなrenderメソッドの使い方まとめ [Rails] hayashino 18/11/24
18/12/01
140
54
68 Rails の session を完全に理解した zettaittenani 18/12/17
19/07/16
184
31
69 Bundlerの使い方 oshou 16/03/27
17/02/03
387
20
70 N+1問題 TsubasaTakagi 17/12/07
17/12/07
188
32
71 モデルやメソッドに名前を付けるときは英語の品詞に気をつけよう jnchito 14/05/28
17/06/27
3076
0
72 Ruby on Rails+ReactでCRUDを実装してみた yoshimo123 18/02/17
19/02/28
240
26
73 Railsのポリモーフィック関連とはなんなのか itkrt2y 16/12/03
18/12/20
310
28
74 【2018年版】macにrbenvを入れてrubyを管理できるようにしちゃう Alex_mht_code 18/04/17
19/06/07
236
21
75 RubyとRailsにおけるTime, Date, DateTime, TimeWithZoneの違い jnchito 14/12/07
18/01/25
1425
0
76 Rails 5.2 で ActiveSupport::MessageEncryptor::InvalidMessage scivola 18/05/24
19/05/27
230
28
77 Webpacker使うなら最低限これだけは知っておいてほしいこと chimame 18/08/07
19/12/18
207
28
78 使えるRSpec入門・その2「使用頻度の高いマッチャを使いこなす」 jnchito 14/11/05
19/07/22
941
0
79 みんなRailsのSTIを誤解してないか!? yebihara 16/12/04
16/12/16
429
29
80 ニコニ立体を直した話 uproad3 19/11/07
19/12/02
230
0
81 Docker + Rails + Puma + Nginx + MySQL eighty8 17/08/25
19/10/28
174
35
82 あなたはDRY原則を誤認している? yatmsu 16/12/06
18/07/29
236
25
83 使えるRSpec入門・その4「どんなブラウザ操作も自由自在!逆引きCapybara大辞典」 jnchito 15/01/01
19/07/22
1096
0
84 Ruby 正規表現の使い方 shizuma 15/07/27
15/07/28
485
25
85 VSCode公式の機能で、リモートサーバにSSHして編集する【Insiders Preview】 suzuki_sh 19/05/03
19/05/12
372
18
86 永久保存版!?伊藤さん式・Railsアプリのアップグレード手順 jnchito 19/08/18
19/10/24
337
37
87 はじめてのRails API c5meru 17/12/16
17/12/16
296
18
88 20万pv/月達成のwebサービスのRailsソースコード、全部見せます! kent_ear 18/07/31
19/08/22
788
7
89 AWS:無料でSSL証明書を取得する方法 iwaseasahi 17/06/03
18/01/13
255
21
90 フロントエンド全然わからないマンが、ちょっとでも見た目のいいWebサービスを作ろうとしてやったこと liukoki 18/03/21
18/03/25
1018
15
91 RubyのModuleの使い方とはいったい shiopon01 16/09/15
16/09/15
264
25
92 Rails enumについてまとめておく shizuma 16/01/07
16/01/07
275
23
93 redirect_to @userが何を省略しているかわかりますか?〜挫折しないRailsチュートリアル7章〜 Kawanji01 18/07/05
20/03/16
168
43
94 実務で学んだRailsの設計・リファクタリング wawoon 17/12/08
19/02/10
203
27
95 あなたがマスターしたのはいくつ? Railsを習得するために必要な技術要素の一覧 jnchito 16/07/06
16/07/26
1175
17
96 railsで多対多のアソシエーションの作り方と、出来ること Kohei_Kishimoto0214 17/01/19
17/06/26
286
18
97 RailsアプリへのRspecとFactory_botの導入手順 Ushinji 18/01/08
19/12/14
208
23
98 [初学者]Railsのi18nによる日本語化対応 shimadama 18/07/31
20/03/22
153
35
99 docker-composeを爆速にする shotat 18/05/13
18/05/13
174
46
100 Railsのルーティングの種類と要点まとめ senou 16/05/20
19/02/05
229
24

  1. 1行目が総数。2行目が直近3ヵ月。 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby】【長期】Qiitaの読んでおかなければいけない記事100選【毎日自動更新】

ページ容量を増やさないために、不具合報告やコメントは、説明記事 に記載いただけると助かります。

順位 記事名
________________________________________
ユーザ 投稿日付
更新日付
LGTM1
1 (下準備編)世界一丁寧なAWS解説。EC2を利用して、RailsアプリをAWSにあげるまで naoki_mochizuki 16/01/08
19/01/17
2591
913
2 プログラミング勉強を加速させる7つの習慣 YudaiTsukamoto 16/12/15
16/12/21
2933
471
3 使えるRSpec入門・その1「RSpecの基本的な構文や便利な機能を理解する」 jnchito 14/10/26
19/07/22
2924
343
4 非デザイナーエンジニアが一人でWebサービスを作るときに便利なツール32選 okappy 14/09/18
15/07/08
6312
308
5 一番詳しいCSS設計規則BEMのマニュアル Takuan_Oishii 17/08/30
19/07/16
787
560
6 [初心者向け] RubyやRailsでリファクタリングに使えそうなイディオムとか便利メソッドとか jnchito 13/11/04
18/03/14
3008
189
7 rails generate migrationコマンドまとめ zaru 14/09/09
18/11/06
1467
216
8 【初心者向け】丁寧すぎるRails『アソシエーション』チュートリアル【幾ら何でも】【完璧にわかる】? kazukimatsumoto 18/11/29
19/12/06
711
511
9 [Rails] deviseの使い方(rails5版) cigalecigales 16/11/13
18/05/17
852
254
10 未経験からRuby on Railsを学んで仕事につなげるまでの1000時間メニュー saboyutaka 18/12/09
19/09/14
1178
488
11 Railsアプリケーションにおけるエラー処理(例外設計)の考え方 jnchito 15/09/28
20/02/03
1557
242
12 Rails開発におけるwebサーバーとアプリケーションサーバーの違い(翻訳) jnchito 15/10/20
15/10/21
1223
203
13 【初心者向け】テストコードの方針を考える(何をテストすべきか?どんなテストを書くべきか?) jnchito 18/05/22
18/06/14
1173
319
14 Railsバリデーションまとめ shunhikita 15/02/24
17/11/15
1037
195
15 高校文化祭の食販で自動注文機を作った話 RyotaroSaito 19/11/15
19/12/22
1304
1304
16 【まつもとゆきひろ氏 特別講演】20代エンジニアのためのプログラマー勉強法のまとめ 2019/3/30 motoki4917 19/03/30
19/10/19
1642
462
17 Rails deviseで使えるようになるヘルパーメソッド一覧 tobita0000 17/05/07
17/05/07
488
274
18 プログラミング初心者歓迎!「エラーが出ました。どうすればいいですか?」から卒業するための基本と極意(解説動画付き) jnchito 16/06/26
19/05/01
1167
218
19 ActiveRecordのjoinsとpreloadとincludesとeager_loadの違い k0kubun 14/09/04
16/02/11
1507
149
20 Rails における内部結合、外部結合まとめ yuyasat 16/09/03
19/01/14
574
204
21 (デプロイ編①)世界一丁寧なAWS解説。EC2を利用して、RailsアプリをAWSにあげるまで naoki_mochizuki 16/01/12
20/01/17
569
203
22 モデルやメソッドに名前を付けるときは英語の品詞に気をつけよう jnchito 14/05/28
17/06/27
3076
119
23 Railsで超簡単API k-penguin-sato 18/06/27
20/02/24
387
324
24 RubyとRailsにおけるTime, Date, DateTime, TimeWithZoneの違い jnchito 14/12/07
18/01/25
1425
118
25 使えるRSpec入門・その2「使用頻度の高いマッチャを使いこなす」 jnchito 14/11/05
19/07/22
941
140
26 使えるRSpec入門・その4「どんなブラウザ操作も自由自在!逆引きCapybara大辞典」 jnchito 15/01/01
19/07/22
1096
127
27 Rails5.2から追加された credentials.yml.enc のキホン NaokiIshimura 18/04/12
18/04/13
413
236
28 脱初心者を目指すVimmerにオススメしたいVimプラグインや.vimrcの設定 jnchito 14/06/08
18/05/15
1938
82
29 RailsアプリをDockerで開発するための手順 togana 16/04/11
17/07/31
684
88
30 Ruby on Rails カラムの追加と削除 azusanakano 16/03/29
16/03/29
310
163
31 【Rails 5】(新) form_with と (旧) form_tag, form_for の違い hmmrjn 18/07/01
18/07/03
392
239
32 bundle install と bundle updateの違いについて lasershow 16/01/21
16/01/21
370
143
33 スタブとモックの違い k5trismegistus 17/04/05
17/04/06
361
165
34 削除済(ID:b1aa2ae143624e551aea) saitoeku3 18/06/18
19/07/05
299
260
35 Rubyの文字列とシンボルの違いをキッチリ説明できる人になりたい Kta-M 16/09/05
19/04/07
441
136
36 【Rails初心者必見!】ひたすら丁寧にデータ取得を説明(find, where) mr-myself 15/09/03
15/09/03
435
121
37 【Rails 5.2】 Active Storageの使い方 hmmrjn 18/06/30
19/08/06
338
218
38 [Docker] 初心者が知っておくと便利かもしれない18の知識 enta0701 17/09/30
19/01/17
376
197
39 使えるRSpec入門・その3「ゼロからわかるモック(mock)を使ったテストの書き方」 jnchito 14/11/21
15/09/29
969
109
40 VSCodeでRuby On Railsを快適に書きたい sensuikan1973 18/10/07
19/06/17
479
225
41 なぜrailsの本番環境ではUnicorn,Nginxを使うのか?  ~ Rack,Unicorn,Nginxの連携について ~【Ruby On Railsでwebサービス運営】 takahiro1127 18/05/13
19/11/13
268
234
42 決定版!!Haml小技まとめ!! yukimura1227 16/04/16
18/11/29
293
156
43 【これが無料?】無料で学べるプログラミング教材・ハンズオン一覧 kocpa 19/06/26
19/07/05
935
935
44 Rubyで%記法(パーセント記法)を使う mogulla3 14/08/23
14/08/23
903
86
45 Bundlerの使い方 oshou 16/03/27
17/02/03
387
121
46 「Railsは終わった」と言われる理由 klriutsa 19/03/05
19/08/22
432
280
47 railsのrenderとredirect_toの違い 1ulce 16/12/02
16/12/02
310
150
48 (DB・サーバー構築編)世界一丁寧なAWS解説。EC2を利用して、RailsアプリをAWSにあげるまで naoki_mochizuki 16/01/10
19/01/17
459
136
49 nil? empty? blank? present? の使い分け somewhatgood@github 13/01/24
13/01/24
1084
100
50 Rails で includes して N+1 問題対策 hirotakasasaki 17/02/10
17/02/11
321
129
51 Ruby on Rails, Vue.js で始めるモダン WEB アプリケーション入門 tatsurou313 19/02/11
19/09/29
273
266
52 Awesome Ruby : 素晴しい Ruby のライブラリ・ツール・フレームワーク・ソフトウェアの数々 hatai 17/07/24
19/11/01
550
110
53 Rubyによるデザインパターンまとめ yuji_ariyasu 18/09/10
19/08/15
525
170
54 [Rails]ransackを利用した色々な検索フォーム作成方法まとめ nishina555 17/03/02
19/05/13
294
144
55 [Ruby入門] 14. 日付と時刻を扱う(全パターン網羅) prgseek 17/04/28
17/05/05
289
146
56 早く知ってたら良かったrailsの技 k-shogo 14/12/18
14/12/18
1125
75
57 Ruby 正規表現の使い方 shizuma 15/07/27
15/07/28
485
117
58 Capybaraチートシート morrr 17/08/19
17/08/19
289
145
59 Railsアプリで Bootstrap 4 を利用する NaokiIshimura 17/11/03
19/08/14
292
146
60 あなたがマスターしたのはいくつ? Railsを習得するために必要な技術要素の一覧 jnchito 16/07/06
16/07/26
1175
98
61 【Rails】form_for/form_tagの違い・使い分けをまとめた shunsuke227ono 15/04/28
16/11/15
834
71
62 Ruby block/proc/lambdaの使いどころ kidach1 13/11/18
17/01/29
1427
83
63 あなたはいくつ知っている?Rails I18nの便利機能大全! Kta-M 17/06/26
19/04/19
350
127
64 知識0から、AWSのEC2でウェブサーバーを構築するまで shunsuke227ono 15/10/26
16/04/24
461
97
65 Railsのポリモーフィック関連とはなんなのか itkrt2y 16/12/03
18/12/20
310
104
66 中規模Web開発のためのMVC分割とレイヤアーキテクチャ yuku_t 14/05/20
17/08/15
1725
67
67 みんなRailsのSTIを誤解してないか!? yebihara 16/12/04
16/12/16
429
101
68 【まつもとゆきひろ氏 特別講演】若手エンジニアの生存戦略に行ってきたので私的メモ DAdDY0055 18/06/23
18/06/27
1244
10
69 Rails enumについてまとめておく shizuma 16/01/07
16/01/07
275
106
70 【初心者向け】これからRailsエンジニアとして成長したい人がすべきこと hc0208 16/03/21
18/10/15
356
103
71 Ruby on Rails 6の主要な新機能・機能追加・変更点 ryohashimoto 18/12/22
19/10/21
291
217
72 【Rails】MySQL2がbundle installできない時の対応方法 fukuda_fu 19/03/21
19/04/10
238
236
73 俺が悪かった。素直に間違いを認めるから、もうサービスクラスとか作るのは止めてくれ joker1007 16/12/15
17/01/08
945
84
74 RubyのModuleの使い方とはいったい shiopon01 16/09/15
16/09/15
264
107
75 rspec-rails 3.7の新機能!System Specを使ってみた jnchito 17/10/23
19/12/14
362
137
76 Railsのjbuilderの書き方と便利なイディオムやメソッド ryouzi 17/11/28
19/01/08
274
139
77 railsで多対多のアソシエーションの作り方と、出来ること Kohei_Kishimoto0214 17/01/19
17/06/26
286
103
78 gem installでpermissionエラーになった時の対応方法 nishina555 18/11/25
19/09/25
220
202
79 ノンプログラマーが3ヶ月でWebサービスを作ってみた tabbyz 15/02/25
16/03/27
1597
56
80 あなたはDRY原則を誤認している? yatmsu 16/12/06
18/07/29
236
110
81 Railsのルーティングの種類と要点まとめ senou 16/05/20
19/02/05
229
103
82 mysql2 gemインストール時のトラブルシュート HrsUed 18/11/28
19/04/16
264
211
83 Ruby のエラーメッセージを読み解く(初心者向け)その 1 scivola 16/03/05
19/08/06
256
106
84 日本正式リリースしたStripeを使ってサブスクリプション型決済システムを実装する tady 16/10/04
18/05/21
394
92
85 find、find_by、whereの違い tsuchinoko_run 18/03/17
18/03/17
216
148
86 はじめてのRails API c5meru 17/12/16
17/12/16
296
116
87 フロントエンド全然わからないマンが、ちょっとでも見た目のいいWebサービスを作ろうとしてやったこと liukoki 18/03/21
18/03/25
1018
83
88 YAMLとは何か? - いつもRailsの設定ファイルで出てくるやつの正体 Yama-to 15/07/27
15/08/08
385
96
89 20万pv/月達成のwebサービスのRailsソースコード、全部見せます! kent_ear 18/07/31
19/08/22
788
60
90 Rubyのメソッドの引数受け渡しまとめ raccy 16/07/17
19/12/25
233
112
91 (Capistrano編)世界一丁寧なAWS解説。EC2を利用して、RailsアプリをAWSにあげるまで naoki_mochizuki 16/02/01
19/11/14
301
100
92 Ruby on RailsのAjax処理のおさらい ka215 15/01/20
19/06/25
728
77
93 AWS:無料でSSL証明書を取得する方法 iwaseasahi 17/06/03
18/01/13
255
118
94 Rails 5 + ActionCableで作る!シンプルなチャットアプリ(DHH氏のデモ動画より) jnchito 15/12/22
16/07/13
644
78
95 今更聞けないpryの使い方と便利プラグイン集 k0kubun 14/12/21
16/01/16
752
60
96 並行処理、並列処理のあれこれ Kohei909Otsuka 18/02/14
18/02/15
215
141
97 正規表現のパフォーマンスの話をされても全くピンと来なかった僕は、backtrackに出会いました。 mochizukikotaro 16/05/28
17/04/04
539
35
98 最速!MacでRuby on Rails環境構築 narikei 15/12/12
19/03/05
318
77
99 Ruby on Rails+ReactでCRUDを実装してみた yoshimo123 18/02/17
19/02/28
240
125
100 【初心者向け】RailsのActive Recordの解説&メソッドまとめ ryokky59 18/10/05
18/10/05
184
175

  1. 1行目が総数。2行目が直近1年。 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Kinx ライブラリ - Math

Math

はじめに

「見た目は JavaScript、頭脳(中身)は Ruby、(安定感は AC/DC)」 でお届けしているスクリプト言語 Kinx。言語はライブラリが命。ということでライブラリの使い方編。

今回は Math です。

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 オブジェクト経由であえて使う必要はないかな、と。

ではまた次回。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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ビューという基本を守った方が良い。
その場合、実装方法には様々な方法があるため、色々試して見るとより理解が深まるかもしれません。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails ウィザード形式導入について 3

はじめに

Rails ウィザード形式導入について 1 はこちらをクリック願います。
Rails ウィザード形式導入について 2 はこちらをクリック願います。
チーム開発でフリマサイトを開発致しました。
その際、ユーザーの新規登録画面でウィザード形式を導入致しましたので、内容を整理します。
もうすでにご存知の方、省略の仕方等ご存知でしたら、ご教授願います。

前提

  • ユーザー情報(User)については 以下 A と記述します。
  • 住所情報(Destination)については 以下 B と記述します。

Bの登録の各アクション(create)とビュー(new,create)

ルーティング設定(new,create)

  • B情報を登録するページを表示するnew_destinationアクションのルーティングを設定します。
  • また、B情報を登録するcreate_destinationアクションのルーティングも設定します。
config/routes.rb
Rails.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"
end

B情報のビューファイルの作成(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.rb
class 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

  # 省略
end

2ページ目で入力した住所情報のバリデーションチェック
  • 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かと!

さいごに

日々勉強中ですので、随時更新します。
皆様の復習にご活用頂けますと幸いです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【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)

最終目標

最終的にできて欲しいのは以下。

  1. 検索ボックスにキーワードを入力する
  2. キーワードに基いた検索結果が投稿フォームの下に表示される

そのために必要な処理

  1. 検索フォームにキーワードを入力
  2. キーワードをコントローラ側で受け取る
  3. 受け取ったキーワードを元にAPIを叩く
  4. 叩かれたAPIから情報を取得する
  5. 取得した情報を投稿画面に渡す
  6. 渡された情報で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.rb
module 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
end

get_urlは引数にkeywordが設定されており、画面から入力されたパラメータを受け取ってAPIの#{keyword}部分に渡されます。

HTTParty.get(url)でAPIを叩いて情報を取得します。
このHTTPartyは、自動でjsonを解析してrubyのhashに変換してくれる優れもの。

#api関連
gem 'json'
gem 'httparty'

gemをインストールしときましょう。

コントローラーに取得した情報を渡す

検索フォームから受け取ったパラメーターを先ほど作成したモジュールを経由してAPIを叩き、コントローラーで取得します。

posts_controller.rb
require '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.rb
def url_from_keyword
    keyword = params[:keyword]
    BooksApi.get_url(keyword)
end

これはパラメーターを受け取って、その情報を先ほど作成したモジュールに引数で渡してAPIの情報を取得する処理を行っています。

しかし、フォームから送信するパラメーターを直接ここに投げるわけではありません。

それが先ほどのmethod:getの話につながります。

newアクション

posts_controller.rb
def new
  if @results.present?
     @post = Post.new
  else
     @post = Post.new
     @results = url_from_keyword
  end
end

newアクションではAPIの情報があるときとない時で処理を分けています。

ない時は@rersultsに初期値で空配列を入れており、処理はPost.newだけです。

APIが叩かれた場合はその情報を@resultsに入れてるので、Post.newと@resultsの情報の表示処理を行います。

先ほど検索フォームを作成した際、methodをgetに設定していたのはこのためです。

routes.rb
resources :posts do
    post 'add' => 'likes#create'
    delete '/add' => 'likes#destroy'
end

newアクションは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は以前書いたいいね機能とほとんど同じです。

【Rails】いいね機能の実装

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.rb
class NilClass
    def [](*)
      nil
    end
end
posts_controller.rb
class PostsController < ApplicationController
    @results = []
    require 'nil_class'
...

モジュールを作ったディレクトリにnilclass用のファイルを作り、それをrequireで呼び出してます。

これでとりあえず表示は問題ないです。

まとめ

今回このポートフォリオを作る中で結構ミソのとこではあったので、自分なりに色々がんばりました。

ぶっちゃけコードは美しくないのでそこはこれから改善したいと思います…。

ひとまず作品自体は大体完成したので、あとはデプロイだけです。

が、AWSのデプロイが全然できなくて絶賛躓き中でございます。

無事デプロイが完了しましたらその辺の奮闘記も書きたいと思いますので、その時はどうぞよろしくお願い致します。

ではでは。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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.5

2.5.1の隣に書いてあることを確認すると、
「/Users/~/.ruby-version」でRubyのバージョンを設定しているよ、とわかります。

解決法1 「/Users/~/.ruby-version」ファイルの削除

Finder、ターミナルからファイルを削除すれば解決できます。
ただし、ファイル名の前に「.」がついているので、隠しファイルになっています。
そのため、Finder、ターミナルにデフォルトで表示されません。

解決法2 ディレクトリごとのRubyバージョン指定を解除

下記のコマンドを実行し、ディレクトリごとのRubyバージョン指定を解除してあげれば解決

rbenv local --unset
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

While文の基本

環境,前提

Ruby 2.5.1
MacOS Mojave Ver.10.14.6

本記事はRubyがインストールされた前提の記事です。
Rubyをインストールしたあと、とにかくRubyをいろいろ触ってみて慣れていくための記事です。お役に立てば幸いです。

while文の基本

sample.rb
while 条件 do
   // 繰り返す処理
end

では1から10までの合計をwhile文を用いて算出してみます。

sample.rb
sum = 0
i = 0
while i <= 10 do
sum += i
i+=1
end
puts sum

実行結果は以下のように55となります。

Tarminal
55

while文とfor文の使い分け

どちらも繰り返し処理の際に用いられるものですが、どういった使い分けが良いでしょうか?以下のように使い分けるのが良いと思います。

・繰り返し回数が決まっておらず、条件を満たす限り回すのはwhile文
・回数が明確に決まっている場合はfor文

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ブロックを使う配列のメソッド

mapメソッド

戻り値をそのまま新しい変数に入れることができる。

ruby
numbers = [1,2,3,4,5]
new_numbers = numbers.map { |n| n * 10 }
puts new_numbers  #=> [10,20,30,40,50] 


selectメソッド

各要素を評価し、真の要素を戻り値として配列にして返すメソッド
rejectメソッドはselectの反対で真になった要素を除外した配列を返す。

ruby
numbers = [1,2,3,4,5]
even_numbers = numbers.select { |n| n.even? }
puts even_numbers  #=>   [2,4]


  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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
(こっちのほうが詳しいとか言わない)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【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
(こっちのほうが詳しいとか言わない)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ワンライナーへのリファクタリング

対象読者

プログラミング初学者

リファクタリングとは

外部から見た時の挙動は変えずに、プログラムの内部構造を整理すること
構造の階層化やプログラム内の要素につける名前を簡潔なものに書き換えるなどがある

リファクタリングのメリット

  1. コードの煩雑さ(性能劣化)が低減するため、トラブルを起りにくくなる
  2. コードを理解しやすくなり、引き継ぎ時の手間が減る
  3. 修正、追加をより早く、正確に行えるため、トラブル時の対応が速くなる

リファクタリングのデメリット

チーム開発の場合、メンバーが同じ修正方法の認識を持っていないと、各々が考える方法での修正となり、結局ソースコードを全体でみるとバラバラのままになる

本題:ワンライナーへのリファクタリング

以下のコードに関して、リファクタリングを行っていきます。

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]

今回参考にさせていただいたサイト

Ruby 2.7.0 リファレンスマニュアル.

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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.rb
module 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のインスタンスを取得できないかと考える

ソースを確認し、簡単には無理そうだなと理解

https://github.com/jetruby/apollo_upload_server-ruby/blob/master/lib/apollo_upload_server/wrappers/uploaded_file.rb

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)に処理を書くかと結論の方法を採用

もし他にいい方法があるよ!って場合はご教授いただけると
ありがたいです。
よろしくお願いします!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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.rb
class 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.rb
class TasksController < ApplicationController

  def index
    @task = Task.new
    # モデルに定義したscopeはメソッドのように呼び出せる
    @tasks = Task.incoming.order(start_at: :asc)
  end

# 以下省略

参考リンク

enumリファレンス(英語)
enum_help Githubリポジトリ
Rails ModelのScope(スコープ)の使い方

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

素人が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/)

  

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MVCのリファクタリング

ビューのリファクタリング

ビューファイルで複雑な呼び出しを行っている場合

【例】

app/views/articles/index.html.erb
<% Article.where(status: 1).order(likes_count: :desc).limit(10).each do |article| %>
  <%= article.title %>
<% end %>

この例では「表示処理を行う」ことを責務としたビュー上で、データの呼び出しに関する複雑な処理が書かれています。
このような複雑な処理は、「データ処理を行う」ことを責務としたモデルに記載します。なぜかというとビューファイルに複雑な記述があると、コードの視認性が悪くなります。また、モデルに記述すると、様々なアクションで用いることができます。
また、モデルに定義した処理を行った上で、コントローラでインスタンス変数として定義します。
model

class Article < ActiveRecord::Base
  scope :popular, -> { order(likes_count: :desc) }
  enum status: { draft: 0, published: 1 }
end

controller

def index
  @articles = Article.published.popular.limit(10)
end

view

<% @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.rb
def current_user_has?(instance)
  user_signed_in? && current_user == instance.user
end
app/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ではビューで使えるヘルパーメソッドが使用できます。
helper

def 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
end

view

<%= 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.rb
class 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
end
app/controllers/top_controller.rb
class 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.rb
module 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
end
app/controllers/products_controller.rb
class ProductsController < ApplicationController
  include CurrentCart
  before_action :set_cart
end
app/controllers/top_controller.rb
class TopController < ApplicationController
  include CurrentCart
  before_action :set_cart
end

ユーザーのカート情報を扱うためにそれぞれのコントローラでこのset_cartを定義する必要がありますが、定義したCurrentCartを使用したいコントローラで読み込むだけでそこに定義されているメソッドを使用することができるようになります。

複数のコントローラに同じ処理が記述されている場合(継承)

共通の処理を持つコントローラが同じ親コントローラを継承していれば、親コントローラに記述することで処理を共通化することができます。

app/controllers/sales_controller.rb
class SalesController < ApplicationController
  before_action :authorize_owner

  private

  def authorize_owner
    redirect_to root_path unless current_user.owner?
  end
end
app/controllers/customers_controller.rb
class 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.rb
def ApplicationController < ActionController::Base

  private

  def authorize_owner
    redirect_to root_path unless current_user.owner?
  end
end
app/controllers/sales_controller.rb
class SalesController < ApplicationController
  before_action :authorize_owner
end
app/controllers/customers_controller.rb
class CustomersController < ApplicationController
  before_action :authorize_owner
end

複数のアクションに同じ処理が記述されている場合

同じコントローラ内で同じような処理が繰り返し記述されている場合はcallbackを用いて共通化します。
controller

def 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を利用して共通化します。
controller

def 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

  ~省略~

end

set_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.save

after

# 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.rb
class User < ActiveRecord::Base
  def full_name
    "#{family_name} #{first_name}"
  end

def full_name_kana
    "#{family_name_kana} #{first_name_kana}"
  end
end

Decorator(デコレーター)とはビューとモデルの中間に位置し、モデルやビューなどに実装されやすい表示ロジックやフォーマットなどの責務を引き受けるクラスです。
モデルにビューでしか使用しないメソッドが増えていくことがあります。上のfull_nameやfull_name_kanaと言ったメソッドがその例です。こうしたメソッドをデコレーターに移動することでコードの見通しが改善されます。
Railsでデコレーターを使用する場合にはdraperやactive_decoratorと言ったgemを使う方法が一般的です。今回はdraperを使った例を記述します。
active_decorator Github リポジトリ
「デコレーター」を導入するためのgemです。
【例】

app/decorators/user_decorator.rb
class UserDecorator < Draper::Decorator
  delegate_all

  def full_name
    "#{family_name} #{first_name}"
  end

  def full_name_kana
    "#{family_name_kana} #{first_name_kana}"
  end

end
app/controllers/users_controller.rb
class UsersController < ApplicationController
  def show
    @user = User.find(params[:id]).decorate
  end
end
app/views/users/show.html.erb
<%= @user.full_name %>
<%= @user.full_name_kana %>

Validator(バリデーター)

【例】

app/models/article.rb
class Article < ActiveRecord::Base
  validates :url, format: { with: /\A#{URI::regexp(%w(http https))}\z/ }
end
app/models/products.rb
class Article < ActiveRecord::Base
  validates :url, format: { with: /\A#{URI::regexp(%w(http https))}\z/ }
end

モデルの役割の一つにバリデーションがあります。バリデーションとはデータの整合性を保つために、データを検証する機能のことです。
あるモデルのバリデーションに複雑な処理があったり、複数のモデルに共通のバリデーションが存在する場合にはそれらをモデルから切り離すことでリファクタリングが可能になります。
【例】

app/models/articles.rb
class Article < ActiveRecord::Base
  validates :name, url_format: true
end
app/models/products.rb
class Article < ActiveRecord::Base
  validates :url, url_format: true
end
app/validators/url_format_validator.rb
class 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.rb
class event < ActiveRecord::Base
  validates_with RangeValidator
end
app/validators/range_validator.rb
class RangeValidator < ActiveModel::Validator
  def validate(record)
    unless start_time < finish_time
      record.errors.add :base, "finish_timeはstart_timeよりも後に設定してください。"
    end
  end
end

Callback(コールバック)

【例】

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で解読を行っています。このようにコールバック同士に関係性がある場合には別の一つのクラスとして扱うことによって関係性を明確にすることができます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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

初心者のため稚拙な説明で申し訳ございません。
よろしくお願い致します。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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)が呼び出された

結論

呼び出し元の名前空間から内→外へと探しにいくようだ。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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)が呼び出された

結論

呼び出し元の名前空間から内→外へと探しにいくようだ。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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!!!!!!!!'


結論

どちらも呼び出し可能

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rubyのクラスにおける@とselfの整理

基本的に、@はインスタンス変数を、selfはメソッドを呼び出す。ただし、attr_accessorで指定したインスタンス変数に関してはselfで呼び出せる。

その心は...

attr_accessor hogeは、インスタンス変数hogeのアクセッサとしてhoge, hoge=メソッドを定義する。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

@keymoon氏の【全方位木DP】のRuby実装

【全方位木DP】明日使える便利な木構造のアルゴリズム
上記事の Ruby への単なる移植です。

コード

Ruby
class 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.rb
edges = [[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)

おかしなところがあったら教えて下さい。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Kinx ライブラリ - String

String

はじめに

「見た目は JavaScript、頭脳(中身)は Ruby、(安定感は AC/DC)」 でお届けしているスクリプト言語 Kinx。言語はライブラリが命。ということでライブラリの使い方編。

今回は String です。

文字列操作の基本インターフェース。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) strsep を区切り文字として分割し、配列として返す。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 で書きたくない処理の一つですね。

ではまた次回。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む