Ruby on Rails開発のインターン (Day 28)
こんにちは、皆さん!
今日はマーカー変数を効率よく定義する方法を探して、もう少しスマートにテストを書いていけるようにする。あと、マップ上でマーカーをフィルターする方法とそのときに使うチェックボックスとラジオボタンをCapybaraテストでどうやってコントロールするのかも勉強しないとな。
- トピック:
グーグルマップ上でマーカーをフィルターする方法
Capybaraテストでセレクターを使ってHTML内のものをアクセスする
- 疑問:
- 問題:
- マップ上にマーカーがいくつあるのか数える方法を探す必要がある(解決)
- 学習した内容:
- どこをどうやって変えることでマップ上でマーカーをフィルターすることができるか
- 今後やってみたいこと:
- マップだけでなく、自分のプロジェクトでもフィルターを実行する
- グーグルマップ上でマーカーをフィルターする方法に関するブログを書く
- リソース:
グーグルマップ上でマーカーをフィルターする方法
Advanced Google Maps with JavaScript: Filtering and Displaying Information | appendTo
このサイトのおかげでマップ上でフィルターする方法をだいぶ楽に理解できた。
はじめに、まずはJavaScriptをユーザーの選択次第で実行してHTMLのチェックボックスやラジオボタンの状態の変化に対応する必要がある。次に、フィルターされたシチュエーション次第でそれぞれのマーカーを表示するのか、それか非表示にするのか決める必要がある。
CodePenのこのサイトのコードを見ていくと、次のようなことが分かった。
サイト上のシステムはこうやって動いていた。
- 一つの配列にハッシュの形でそれぞれのシチュエーションをブーリアン型で入れて、そのシチュエーションでフィルターしているかどうかを記録する。マーカーはぞれぞれ自身にシチュエーションごとにその条件を満たしているかどうかをブーリアンで決めている。もし、ユーザーがフィルターの選択肢のどれかをクリックしたら、配列内のその値の真偽がひっくり返るという感じ。
- クリックした後、配列内の値が変わり、マーカーを一つ一つ見ていき、そのマーカーが配列内の条件を満たしているかどうか見る。この場合は配列内のすべての真のシチュエーションに対して、そのマーカーがそのすべての真のシチュエーションにおいて真であるのなら表示する。
setVisible(arg)
関数を使ってマーカーが見えるかどうかを調整する。
こうやって、箇条書きで書きだすと長いコードもだいぶわかりやすくなってくる。でも、それぞれの動作をするのにさらに複雑に関数が絡み合っている印象を受けた。
これに関しては内容も深いわけなので、のちにブログを書きたいなと思っている。
Capybaraテストでセレクターを使ってHTML内のものをアクセスする
少し探してみたら、下記のようにコードを書くのが簡単だと思った。
page.should have_css('h1', :count => 1)
この例はページ内に一つだけh1
タグがあることを確認する。多くても、少なくてもダメで、必ず一個だけ。
もうお分かりだと思うが、カッコ内の一つ目がどんなHTML要素を探すかで、二つ目がどれだけあるかである。なので、"center"というクラスを持つ要素がちょうど二つあることを確認したいのなら、
page.should have_css('.center', :count => 2)
またCSSで要素を選択するように書くこともできる(というかそれが本質)
# <div><div class="center"></div></div> page.should have_css('div div.center', :count => 1) # <input type="submit"></input> page.should have_css('input[type="submit"]', count => 1)
これのおかげでマーカーにたどり着くためのCSSのセレクターを見つけることができた。この例はマーカーの写真を選択するというもの。
(後日、別のものに変更した。たまにセレクターが変わることがあるっぽいのでディベロッパーツールでしっかり確認しよう。)
page.should have_css('div.gmnoprint img[src="/assets/default-map-marker-0ec32d1d8c746e755dc1207a63f227cb519433ad4879170711c8d2bc66e1c997.png"]', :count => 1)
他の選び方も試したが、見えないものの重複があって、数が合わなかった。で、結果的にこれになった(笑)
まとめ
それで、プログラミングに話を戻すと、グーグルマップ上でマーカーをフィルターする方法とマップ上のマーカーの数を確認する方法について学んだ。これのおかげで僕のマーカーのテストを一つ上のレベルまで押し上げてくれた。只今、なぜかわからないが、Railsのコンソールを開いて作ったマーカーがテストを始めると消えているので、そこら辺について、明日も頑張っていこうと思う。
ご精読ありがとうございました。では、また次回まで✌
Ruby on Rails開発のインターン (Day 27)
こんにちは、皆さん!
7週目がやってきた。インターンも残りわずかだ。もうあと2週間だから時間も限られている。今やっているマップテストをどこまでやるべきなのかもよくわからない。思い返すと、このインターンはすごくよかったし、思っていたよりずっと短かった気がする。時間がたつのって本当に早いね(笑)
- トピック:
- 疑問:
- 問題:
- 学習した内容:
- テストが始まる前に変数をあらかじめ定義する
- 今後やってみたいこと:
- リソース;
テストで使われる変数をあらかじめ定義する
テストでこの機能を使おうと思ったのは、多くのシチュエーションがあり、それぞれに対するマーカーが必要だし、いくつかのテストで同じものを使いたいと思ったからだ。
少し探してみたら、下記のようなテンプレが出てきた
before(:each) do # your code here end
それで、僕は下記のを試した
before(:each) do place = Place.find(1) end
その後、テスト内でその変数を使おうとしたら、下記のようなエラーが返ってきた。
NameError: undefined local variable or method `place' for #<RSpec::ExampleGroups::TheSigninProcess:0x0055ddbc033078>
スペルミスはなかったのですごくおかしな感じがしたのだが、後になって、インスタンス変数しかこのような役割を果たすことはできないとわかった。つまり、あらかじめ定義しようとしている変数の前に@
をつける必要があったのだ。よって、下記のが正しい。
before(:each) do @place = Place.find(1) end
これで僕の場合はうまくいき、同じ変数の定義を避け、コードがずっとよく見えるようになった。
まとめ
ご精読ありがとうございました。では、また次回まで✌
Ruby on Rails開発のインターン (Day 26)
こんにちは、皆さん!
今日のフォーカスはどうやってCapybaraテストからコントローラー内のインスタンス変数にアクセスすることができるかだ。それと、今日の朝、新たなウェブサイトのベースを作らないかと相談されたので、内容の少ない比較的新しいウェブサイトを作る機会があるかもしれない。
- トピック:
- 疑問:
- 問題:
- Capybaraテストからコントローラー内のインスタンス変数にアクセスできない(代わりの方法で解決)
- 学習した内容:
- 今後やってみたいこと:
- リソース:
コントローラーの変数を使う代わりに
僕がやったことはとても基本的なことで、テストコードを書いているファイル、つまり、specファイルがルビーファイルであること。これって、つまり、コントローラーでやれることと同じことができる。だから、下記のようにマーカーを取り出すというコードに変更した。
@places = Place.all
なんとなく、面白く感じるのはこんな基本的なことに気づくまでに2,3日かかったってこと。もっと視界を広く持つべきだね。
以前、ブログで出したコントローラー内のインスタンス変数をアクセスするジェムはRails 5から消されたようだ。StackOverflowでその内容に言及したものがあった(英語版)。
Testing what instance variables are set by your controller is a bad idea. That's grossly overstepping the boundaries of what the test should know about. You can test what cookies are set, what HTTP code is returned, how the view looks, or what mutations happened to the DB, but testing the innards of the controller is just not a good idea. - David Heinemeier Hansson
簡単に言うと、コントローラー内の変数にアクセスできるということはテストがしていいことの範囲を超えるそうだ。テストというのはそもそも決められたデータをテストするためにあるのであって、それに対する特定の値の一致が求められているのだ。
テストが何をし、どうやって機能しているのかを見直すいいチャンスだったと思う。こうやって、たまには基本に戻るべきだね。
彼はChromeのディベロッパーツールを開いて、Network
というセクションを開いて、Network
セクションの真下にあるPreserve log
というものをクリックした。
そして、彼はウェブサイトをリロードして、そのツール上で下記のような内容のものが出てきた。
これはどのページがどのHTTPリクエストでプロセスされたのか教えてくれるため、エラーがどこにあるか見つけるときに役立つ。
そして、そのリンクにクリックすると、HTTPリクエストの詳細を表示してくれる。
これのおかげで、無事エラーがどこで発生しているかわかり、今のサイトがPOSTリクエストを出したが、失敗したのが分かった。つまり、これでこのサイトが定義されていない"/groups"というPOSTリクエストをしようとしたことが分かる。
まとめ
毎日何がしたいのかというリストなどを作り、日々しっかり管理する必要がある気がする。じゃないと、やりたいことが多すぎて、結局大事な次のものが始めれなくなっちゃう気がする。よい管理方法を見つけれるといいな。
ご精読ありがとうございました。では、また次回まで✌
Ruby on Rails開発のインターン (Day 25)
こんにちは、皆さん!
今日は問題なく動いているAPI キーを使う許可を取ろうと思う。そう簡単に一個くれるのかどうかはよくはわからないが。代わりの何かの手段を提案してくると予想しているが、とにかくこの問題にもうちょっとちゃんと取り組んでほしいなと思う。じゃないと、先に進めないし。
- トピック:
- 疑問:
- 問題:
assign
関数が使えない
- 学習した内容:
- テスト時にコントローラー内のインスタンス変数を直接使うことができなく、いくつかの関数を使う必要がある
- 今後やってみたいこと:
- リソース:
rails-controller-testing
ジェムでテスト時にコントローラー内のインスタンス変数にアクセスする
少しネットで探してみると、rails-controller-testing
というジェムを使うべきだそう。その後、下記のようにassigns
関数を使うことでインスタンス変数にアクセスするそう。
assigns(:markers)
しかしながら、これに関して、僕の場合はNo method defined assigns function
というエラーが返ってきた。よって、またこの関数について詳しく探っていかないといけないという感じだね。
まとめ
ご精読ありがとうございました。では、また次回まで✌
Ruby on Rails開発のインターン (Day 24)
こんにちは、皆さん!
今日はいろんな方法試してマップ上にマーカーを追加してみようと思う。いいの見つけれてやることリストの次のものに移れるといいな。
一方で自分のウェブサイトも作っているのでそちらも早くやりたいな。だから、仕事を早く終わらせようというモチベーションにもなっている(笑)。
- トピック:
- 疑問:
- 問題:
- GeocoderがAPIキーの問題があるのでデータベースにデータを追加できない
- 学習した内容:
- punditジェムを使って見やすいコードのままユーザーのアクセス制限を行うことができる
- 今後やってみたいこと:
- 自分のアプリでpunditジェムを使ってみる
- リソース:
punditジェムのインストール
pundit
はすごくよく形成されたジェムであり、それを使って、編集ボタンが見えるかどうかなどのユーザーのアクセス制限を行うことができる。punditを使うには、まず、下記のようにジェムをGemfile
に入れる。
gem "pundit"
続いて、いつも通りのbundle install
。
そしたら、app/controllers/application_controller.rb
に行き、下記のを入れる。
include Pundit protect_from_forgery with: :exception
次に、ターミナルで下記のコマンドを実行する。
rails g pundit:install
これでいくつかの設定をセットアップしてくれるし、app/policies
も作成してくれる。
これで、基本的なセットアップは完了。
punditの機能を使う
例えば、Postというモデルがあったとしよう。これをPostを作ったユーザーのみがアクセスできるようにしたいとする。
app/models/post.rb
の中に下記のような1行が入っていることでしょう。(ユーザーがたくさんのPostを作るため)
belongs_to :user
なので、Postオブジェクトから@post.user
のようにそれを作ったユーザーにアクセスすることができるでしょう。
ここで、一つapp/policies/post_policy.rb
というファイルを作り、下記のようなコードを入れる。
class PostPolicy < ApplicationPolicy def initialize(user, post) @user = user @post = post end def edit? return true if @user = @post.user end def destroy? return true if @user = @post.user end end
つまり、これらの関数は現在ログインしているユーザーがPostを作成したユーザーである場合のみTrueを返してくる。
そしたら、今度はapp/views/posts/show.html.erb
に行き、下記のコードを追加する。
<%= link_to "Edit", edit_post_path(@post) if policy(@post).edit? %> <%= link_to "Delete", destroy_post_path(@post) if policy(@post).destroy? %>
これが何を表すのかというと、先ほど述べたようにログインしているユーザーがPostを作成したユーザーでない限り、この2行の最後の部分はTrueにならない。だからif文もその時にしか成り立たない。なので、ログインしているユーザーがPostを作成したユーザーでない限り、この2つのボタンは表示されないということである。
まだまだpunditでコントローラーのアクセス制限を設定したりでき、より複雑だがきれいなコードを書くことができる。
この投稿でそこまではカバーできないが、Githubから参照してみてください。
まとめ
明日になってまだAPIキーの問題への解決策が見当たらなければ、彼らのキーを使わせてもらえるように呼び掛けてみようと思う。
ご精読ありがとうございました。では、また次回まで✌
Ruby on Rails開発のインターン (Day 23)
こんにちは、皆さん!
長い週末が終わり、また職場に戻ってきた。最近なぜかわからないが、マネージャーともう一人のディベロッパが全く連絡を取り合わないからやることリストも更新されていなくて、少し心配だ。すぐに対処してくれるといいが。
- トピック:
- 疑問:
- 問題:
- GeocoderがAPIキーの問題でデータベースにデータを足すのを拒否してくる
- 学習した内容:
- Railsでオートログアウトを実行する方法
- 今後やってみたいこと:
- リソース:
オートログアウトの仕組み
最初にユーザーが戻ってきたときにその前にオンラインだったのが何分前なのかを知る必要があるからユーザーがオンラインになった時の時間をまずは記録する。下記のようにね。
session[:active_time] = Time.now
毎回ユーザーがオンラインになるたびにこの時間を更新するんだぞ
その後、ユーザーがアクティブになった時に下記のような計算をすることでいったいどれだけの時間がたったのかがわかる。
time = Time.now.to_time - session[:active_time].to_time
Time.now
はその時の時間を返してきてくれて、session[:active_time]
は過去のユーザーがアクティブだった時間を返してくれる。つまり、この二つの値をもとに最後にアクティブだった時からどれだけ経ったのかを計算できる。
最後にすることは、これを自分の指定したい長さの時間と比べればよい。例えば、三十分後にオートサインアウトしてほしいのなら
if time > 30.minutes log_out end
まとめ
とりあえず、今、マーカーは問題ないことが分かったが、なぜかgeocoder曰く、APIキーにブロックされて新しいマーカーのデータをデータベースに足すことができない。
クレジットカードをAPIキーに登録しないといけないのかな?
今のところ、これへの対処法はわからないな。
ご精読ありがとうございました。では、また次回まで✌
Ruby on Rails開発のインターン (Day 22)
こんにちは、皆さん!
今日は同僚のインターンに来てる人が今日でラスト1日になるのでみんなとランチに行くことになっている。楽しみだな。
一方で、もうマネージャーの修正を待ってもいられないので、エラーになっている部分をコメントアウトして、自分の書いたコードをテストしていこうと思う(笑)。
- トピック:
- 疑問:
- 問題:
- 学習した内容:
- エラーページのレイアウトをコントロールするジェムが存在する
- 今後やってみたいこと:
- リソース:
Capybaraテストで
native
関数でCSSスタイルの値をより簡単に取り出す
map_width_px = find("#map").style("width")
しかし、なぜか職場のプログラムだと下記のようなエラーが出てくるんですよね
NoMethodError: undefined method `style' for Obsolete #<Capybara::Node::Element>:Capybara::Node::Element
で、それで以前このようなコードの中に出てきたnative
関数を使用してみた。そしたら、面白いことにこれでうまくいったというね。しかもよりいいと言うくらいのものだった。やったことは上記のコードを下記のようなものに変えただけ
map_width_px = find("#map").native.style("width")
これで僕の場合はうまくいき、さらに、便利なことにハッシュ(この場合、{"width": "400px"})ではなく、widthを直接返してくれた(この場合は、”400px”)
でも、結局上記のようなエラーが発生した理由はわからなかった。
とりあえず、このようなnative
関数を使う形の運用はハッシュへのアクセスの1ステップを飛ばせるからコードを書くのを楽にしてくれるのだなと感じた。
まとめ
仕事に関しては、エラー部分を取り除いてテストを始めた。そして、テストコード中に修正する部分があるなと思ったので、それの修正もした。そして、今週最後の日であり、3連休が待っているので、しっかり休んでまた火曜日に備えるぜ!
ご精読ありがとうございました。では、また次回まで✌