letter_openerの設定と起動
letter_opener_webは、開発環境用で実際にメールを送信して確認できるgemです。
letter_opener_webを使用すると、/letter_openerへアクセスしてメールが届いているか確認することができます。
###実際にletter_opener_webをインストール
letter_opener_webは開発環境でのみ使用するので、groupブロックで囲むことによって、開発環境のみ適用するように定義します。
(gemfile)
```
省略
group :development do
gem 'letter_opener_web'
end
```
ルーティングの設定
(routes.rb)
```
# 省略
if Rails.env.development?
mount LetterOpenerWeb::Engine, at: "/letter_opener"
end
# 省略
```
開発環境でメール送信の際、letter_opener_webを使用するように設定。
(config/environments/development.rb)
```
config.action_mailer.default_url_options = { host: 'localhost3000' }
config.action_mailer.delivery_method = :letter_opener_web
```
/letter_openerにアクセス。
https://imgur.com/a/oeQNn
scaffoldで簡単お問い合わせ機能
rails db:create rails new ののち。。
$ rails g scaffold Contact name:string email:string content:text
ファイルがいっぱいできる。
Running via Spring preloader in process 17820 invoke active_record create db/migrate/20171118042216_create_contacts.rb create app/models/contact.rb invoke test_unit create test/models/contact_test.rb create test/fixtures/contacts.yml invoke resource_route route resources :contacts invoke scaffold_controller create app/controllers/contacts_controller.rb invoke erb create app/views/contacts create app/views/contacts/index.html.erb create app/views/contacts/edit.html.erb create app/views/contacts/show.html.erb create app/views/contacts/new.html.erb create app/views/contacts/_form.html.erb invoke test_unit create test/controllers/contacts_controller_test.rb invoke helper create app/helpers/contacts_helper.rb invoke test_unit invoke jbuilder create app/views/contacts/index.json.jbuilder create app/views/contacts/show.json.jbuilder create app/views/contacts/_contact.json.jbuilder invoke test_unit create test/system/contacts_test.rb invoke assets invoke coffee create app/assets/javascripts/contacts.coffee invoke scss create app/assets/stylesheets/contacts.scss invoke scss create app/assets/stylesheets/scaffolds.scss
マイグレーションはする必要がある。
rails db:migrate
メイラーを作成
rails g mailer ContactMailer
mailers/contact/mailer.rbに追記。 contact_mailメソッドにおいて引数を受け取っている。 インスタンス変数は、view(メール本文)で使用するために定義している。
class ContactMailer < ApplicationMailer def contact_mail(contact) @contact = contact mail to:"自分のメールアドレス",subject:"お問い合わせの確認メール" end end
メイラーのviewを作成 ・これは、送信されるメールの本文です。 (app/views/contact_mailer/contact_mail.html.erb)
<h1>お問い合わせが完了しました。</h1> <h4>name:<%= contact.name %></h4> <h4>お問い合わせ内容の確認</h4> <p>content:<%=@contact.content %></p>
お問い合わせをした時にメイラーが呼び出されるように実装。 ・redirect_toにパスではなくインスタンス変数を渡している。これをrailsで勝手に判断してshowを表示してくれる。 ・ここではjsonは特に使用していない。
# POST /contacts # POST /contacts.json def create @contact = Contact.new(contact_params) respond_to do |format| if @contact.save ContactMailer.contact_mail(@contact).deliver#追記 format.html { redirect_to @contact, notice: 'Contact was successfully created.' } format.json { render :show, status: :created, location: @contact } else format.html { render :new } format.json { render json: @contact.errors, status: :unprocessable_entity } end end end
(まとめ) 1.contacts_controllerのcreateアクションでお問い合わせをデータベースに保存する処理が流れる。
2.1の処理が流れた時ContactMailer.contact_mail(@contact).deliverのメイラーの処理が走り、app/mailers/contact_mailer.rbのcontact_mailメソッドが呼び出される。
3.引数として渡す@contactをcontact_mail(contact)の記述でcontactという引数名で受け取り、contact_mail内の処理が実行される。メソッド内で@contact = contactとしているのは@contactをView(contact_mail.html.erb)で使用するため。
4.処理が一通り流れ、メールがお問い合わせ者に届き、contact_mail.html.erbで記述されているHTMLが表示される。
インスタンス変数が効く範囲の理解が怪しい。
【テストプログラム3】
完成形
(janken2.rb)
# 判定部分のみをクラスに。 PLAYER_INPUT_TO_INTEGER = {'g'=> 1 ,'c' => 2 ,'p' => 3 } MACHINE_INTEGER_TO_INPUT = { 0 => "g" , 1 => "c", 2 => "p"} MACHINE_LIST_JANKEN = ["g","c","p"] GCP_TO_JAPANESE = {'g'=>'グー','c' => 'チョキ','p'=>'パー'} puts "input g or p or c" print "you:" player_gcp = gets.chomp machine_gcp = MACHINE_LIST_JANKEN[rand(3)] class Judge def judgement(player_gcp,machine_gcp) # p @player_gcp player_123 = PLAYER_INPUT_TO_INTEGER[player_gcp] machine_012 = MACHINE_INTEGER_TO_INPUT.invert[machine_gcp] result = (player_123 - machine_012 +3)% 3 case result when 0 return "勝ち" when 1 return "あいこ" when 2 return "負け" end end end judge = Judge.new puts "あなたは#{GCP_TO_JAPANESE[player_gcp]}、私は#{GCP_TO_JAPANESE[machine_gcp]}、" unless judge.judgement(player_gcp,machine_gcp)=="あいこ" print "あなたの" end puts "#{judge.judgement(player_gcp,machine_gcp)}です。"
(test_janken2.rb)
require 'test/unit' require_relative 'janken2' class TC_janken < Test::Unit::TestCase def setup @judge = Judge.new end # def teardown # end def test_janken1 assert_equal("勝ち",@judge.judgement("g","c")) assert_equal("あいこ",@judge.judgement("g","g")) assert_equal("負け",@judge.judgement("g","p")) assert_equal("勝ち",@judge.judgement("c","p")) assert_equal("あいこ",@judge.judgement("c","c")) assert_equal("負け",@judge.judgement("c","g")) assert_equal("勝ち",@judge.judgement("p","g")) assert_equal("あいこ",@judge.judgement("p","p")) assert_equal("負け",@judge.judgement("p","c")) end end
Finished in 0.00094 seconds. ------------------------------------------------------------------------------------------------- 1 tests, 9 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications 100% passed ------------------------------------------------------------------------------------------------- 1063.83 tests/s, 9574.47 assertions/s
エラーfailureなし。
やったこと
メソッドの数だけテストが必要になるから、共通機能は1つのメソッドにまとめた。 具体的にはg/c/p から数字に変換するメソッドを判定のクラスに組み込んだ。 その際に、machineとplayerのじゃんけんの出し手の処理処理が異なったっため、一致させた。
クラスに変数を渡そうとして試行錯誤していたが、クラス直下にメソッドを作成し、そのメソッドに引数を渡すものとした。
直接testを行う部分の記述は複雑な処理を書かずに人間に見てわかりやすいものとした。
クラス内のメソッドで参照するハッシュは定数CONSTとした。
判定部分のクラスと出力は分離した。 クラスの戻り値を受け取って出力するものとした。
謎のend_of_inputエラー。classがcalssになってた。
【テストプログラムを作成2】クラスの変数【ruby】
syntaxエラーが発生。
先輩さん曰く、irbを起動してコピペしてはっつけてみると良いとのこと。
irb(main):001:0> result = (player_123 - machine_012 +3)% 3 SyntaxError: (irb):1: syntax error, unexpected tINTEGER, expecting keyword_do or '{' or '(' result = (player_123 - machine_012 +3)% 3 ^
うーむ、
irb(main):002:0> result = (2 - 2 +3)% 3 => 0
あー、定義してないからか。 でもさっきはできてたぞ?
あ、テスト用に判定部分をメソッド化したからですね。
def judge result = (player_123 - machine_012 +3)% 3 print "あなたは#{gcp_to_japanese[player_gcp]}、私は#{gcp_to_japanese[machine_gcp]}、" case result when 0 puts "あなたの勝ちです。" return "勝ち" when 1 puts "引き分けです。" return "あいこ" when 2 puts "あなたの負けです。" return "負け" end end
色々とインスタンス変数にして見ます。
class Janken @player_input_to_integer = {'g'=> 1 ,'c' => 2 ,'p' => 3 } @machine_integer_to_input = { 0 => "g" , 1 => "c", 2 => "p"} @machine_list_janken = [0,1,2] @gcp_to_japanese = {'g'=>'グー','c' => 'チョキ','p'=>'パー'} def janken_random puts "input g or p or c" print "you:" player_gcp = gets.chomp p @player_input_to_integer player_123 = @player_input_to_integer[player_gcp] machine_012 = @machine_list_janken[rand(3)] machine_gcp = @machine_integer_to_input[machine_012] # puts "machine:#{machine_gcp}" end (略) end
読み込まれません。
クラスの変数?ああ、インスタンス変数っしょwつーかこれからっしょw
ってくらいの理解しかありませんでした。勉強不足。
先輩さん曰く・・
インスタンス変数をクラス内のメソッドでは使えない。
インスタンス変数をクラス直下に定義すると読み込まれない。従ってinitialize内にて定義する。
使うためにはinitialize メソッド内に記述する。 インスタンス変数はクラスからオブジェクトを生成する際にインスタンスごとに異なる変数を格納したい場合に使う。
リファレンスマニュアルより
初期化されていない インスタンス変数を参照した時の値はnilです。
私がインスタンス変数を使用したハッシュ等は、インスタンスごとに値が変更されることはない。
従って・・・
定数CONST や、 クラス変数@@constを使うべきです。
クラス変数を使用してみました。 ほぼクラス変数に。atomが真っ赤
$ ruby janken_exe.rb input g or p or c you:g あなたはグー、私はチョキ、あなたの勝ちです。
一応できたけど、被テストプログラムの構造がテストに向いていなかった。その辺を追記。
雑記
rubyの定数は、定数と言いつつ変更可能。 本当の意味で定数にするにはfreezeメソッドを使用する。
【テストプログラムを作成1】test/unit
作成したじゃんけんプログラムをテストしたい。
エラーに次ぐエラーで勉強になりました
test/unitというgemを使うらしい。これは初めて使うのでインストールされているか確認。
$gem list test *** LOCAL GEMS *** minitest (5.8.5) test-unit (3.1.5)
ありますね。
でもtest/unitとtest-unitは違うし、これでいいのか?
先輩さん曰くtest-unitはrequireする際にはrequire 'test/unit'で問題ないとのこと。
ググっても2種類出て来るので混乱しました。
本題の、test/unit (これだとエラー出ます)
require 'test/unit' require_relative 'janken' class TC_janken < Test::Unit::TestCase def setup @obj = Janken.new end # def teardown # end def test_janken assert_equal("janken",@obj) end end
setup jankenクラスのインスタンスを生成
teardown 今回は使っていないが、setupのあとに呼ばれる。
test_janken テストメソッド。 テストメソッドはtest_で始める必要がある。
assert_equal("janken",@obj) ここで比較している。 文字列とオブジェクトを比較していますから、これだとエラーです。
結局・・・
色々(追記)あってこうなりました。
require 'test/unit' require_relative 'janken2' class TC_janken < Test::Unit::TestCase def setup @judge = Judge.new end # def teardown # end def test_janken1 assert_equal("勝ち",@judge.judgement("g","c")) assert_equal("あいこ",@judge.judgement("g","g")) assert_equal("負け",@judge.judgement("g","p")) assert_equal("勝ち",@judge.judgement("c","p")) assert_equal("あいこ",@judge.judgement("c","c")) assert_equal("負け",@judge.judgement("c","g")) assert_equal("勝ち",@judge.judgement("p","g")) assert_equal("あいこ",@judge.judgement("p","p")) assert_equal("負け",@judge.judgement("p","c")) end end
【ruby】getsで文字列を取得する場合の改行文字
getsによりコンソールで文字列を取得する場合
文字列入力後にエンターキーで確定する。
このエンターキー入力が改行文字としてgetsは取得してしまう。
(test.rb)
str = gets
p str
$ ruby test.rb
腑に落ちない
"腑に落ちない\n"
これを防ぐには、、
gets.chomp
format関数の引数・・%03d"とは
3桁以下の数字を変換する課題(例:4 => 004) にて・・・
puts"数字を入力"
num_i = gets.to_i*2
puts format("%03d", num_i)
formatを初めて使った。
format(format, *arg) -> String
format 文字列を C 言語の sprintf と同じように解釈し、 引数をフォーマットした文字列を返します。
- [PARAM] format:
- フォーマット文字列です。
- [PARAM] arg:
- フォーマットされる引数です。
(ruby リファレンスマニュアルより)
https://docs.ruby-lang.org/ja/latest/method/Kernel/m/format.html
rubyのformatは、c言語のsprintf関数と同じ働きをするらしい。
以下、sprintfの書式
%[nth$][フラグ][幅][.精度]指示子
%
前述の%から始まる文字列は、フォーマット文字列と呼ばれる。
0
フラグには #, +, ' '(スペース), -, 0 の5種類がある。
今回は、数字を右詰にする『0』に該当。
他には、符号付きにする『+』や2進法・4進法等の際にそれを明示する『#』等がある。
3
0以外の数字で始まる数字列は幅指定になります。
幅は生成文字列の長さを示します。
d
末尾のdは指示子と呼ばれ、引数の型を示す。
指示子は大きく分けて以下の通り。
- 文字列を表す指示子: c, s, p
- 整数を表す指示子: d, i, u, b, B, o, x, X,
- 浮動小数点数を表す指示子: f, g, e, E, G
それぞれに細かい意味があるので使う時は調べる必要がある。
ちなみにdは、引数の数値を10進表現の整数として出力。
エクセルの書式のフォーマットを思い出します。
いつもテンプレートしか見ていませんでしたが・・