Ruby on Rails開発のインターン (Day 28)

こんにちは、皆さん!

今日はマーカー変数を効率よく定義する方法を探して、もう少しスマートにテストを書いていけるようにする。あと、マップ上でマーカーをフィルターする方法とそのときに使うチェックボックスラジオボタンをCapybaraテストでどうやってコントロールするのかも勉強しないとな。


  • トピック:

グーグルマップ上でマーカーをフィルターする方法
Capybaraテストでセレクターを使ってHTML内のものをアクセスする

  • 疑問:


  • 問題:
  1. マップ上にマーカーがいくつあるのか数える方法を探す必要がある(解決)


  • 学習した内容:
  1. どこをどうやって変えることでマップ上でマーカーをフィルターすることができるか


  • 今後やってみたいこと:
  1. マップだけでなく、自分のプロジェクトでもフィルターを実行する
  2. グーグルマップ上でマーカーをフィルターする方法に関するブログを書く


  • リソース:
  1. Advanced Google Maps with JavaScript: Filtering and Displaying Information | appendTo


グーグルマップ上でマーカーをフィルターする方法

リソース:
Advanced Google Maps with JavaScript: Filtering and Displaying Information | appendTo

このサイトのおかげでマップ上でフィルターする方法をだいぶ楽に理解できた。
はじめに、まずはJavaScriptをユーザーの選択次第で実行してHTMLのチェックボックスラジオボタンの状態の変化に対応する必要がある。次に、フィルターされたシチュエーション次第でそれぞれのマーカーを表示するのか、それか非表示にするのか決める必要がある。

CodePenのこのサイトのコードを見ていくと、次のようなことが分かった。

サイト上のシステムはこうやって動いていた。

  1. 一つの配列にハッシュの形でそれぞれのシチュエーションをブーリアンで入れて、そのシチュエーションでフィルターしているかどうかを記録する。マーカーはぞれぞれ自身にシチュエーションごとにその条件を満たしているかどうかをブーリアンで決めている。もし、ユーザーがフィルターの選択肢のどれかをクリックしたら、配列内のその値の真偽がひっくり返るという感じ。
  2. クリックした後、配列内の値が変わり、マーカーを一つ一つ見ていき、そのマーカーが配列内の条件を満たしているかどうか見る。この場合は配列内のすべての真のシチュエーションに対して、そのマーカーがそのすべての真のシチュエーションにおいて真であるのなら表示する。
  3. setVisible(arg)関数を使ってマーカーが見えるかどうかを調整する。



こうやって、箇条書きで書きだすと長いコードもだいぶわかりやすくなってくる。でも、それぞれの動作をするのにさらに複雑に関数が絡み合っている印象を受けた。

これに関しては内容も深いわけなので、のちにブログを書きたいなと思っている。

Capybaraテストでセレクターを使ってHTML内のものをアクセスする

以前の投稿でも何回か言っているが、Capybaraテストは主に、ウェブサイト上に見えたものをテストするものだ。だから、マップ上にいくつマーカーがあるのかもこのテストを使って確認することができるはず。

少し探してみたら、下記のようにコードを書くのが簡単だと思った。

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)

他の選び方も試したが、見えないものの重複があって、数が合わなかった。で、結果的にこれになった(笑)

まとめ

今日、朝に他の2人のディベロッパーとスタンドアップミーティング(短すぎて、座る必要がないほどの簡単なミーティング)があった。久しぶりのミーティングは何をするべきか、そして何をやったかを整理してくれて、やることリストがだいぶきれいになった。余談だが、リモートで働いていたディベロッパーがニューファンドランド(カナダのマジで東の端)の方まで旅を進めていたことも知った。ネットで画像を検索してみたが、壮大な自然の景色が広がるきれいな島だった。

それで、プログラミングに話を戻すと、グーグルマップ上でマーカーをフィルターする方法とマップ上のマーカーの数を確認する方法について学んだ。これのおかげで僕のマーカーのテストを一つ上のレベルまで押し上げてくれた。只今、なぜかわからないが、Railsのコンソールを開いて作ったマーカーがテストを始めると消えているので、そこら辺について、明日も頑張っていこうと思う。


ご精読ありがとうございました。では、また次回まで✌



Day 29はこちら↓↓
programming-shop.hatenablog.com


Day 27はこちら↓↓
programming-shop.hatenablog.com

Ruby on Rails開発のインターン (Day 27)

こんにちは、皆さん!

7週目がやってきた。インターンも残りわずかだ。もうあと2週間だから時間も限られている。今やっているマップテストをどこまでやるべきなのかもよくわからない。思い返すと、このインターンはすごくよかったし、思っていたよりずっと短かった気がする。時間がたつのって本当に早いね(笑)


  • トピック:
  1. テストで使われる変数をあらかじめ定義する


  • 疑問:


  • 問題:


  • 学習した内容:
  1. テストが始まる前に変数をあらかじめ定義する


  • 今後やってみたいこと:


  • リソース;


テストで使われる変数をあらかじめ定義する

すべてのテストで使われるし、コードがきれいに見えるからあらかじめ変数を定義するのはすごく役に立つ。

テストでこの機能を使おうと思ったのは、多くのシチュエーションがあり、それぞれに対するマーカーが必要だし、いくつかのテストで同じものを使いたいと思ったからだ。

少し探してみたら、下記のようなテンプレが出てきた

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

これで僕の場合はうまくいき、同じ変数の定義を避け、コードがずっとよく見えるようになった。

まとめ

それぞれのテストの前に変数を定義する方法について学んだ。この知識があれば、これからはもっと良いテストが書ける気がする。しかしながら、どうやったらもっと効率よく変数を定義することができるのかとまだ考えているところだ。一つのマーカーを作るのに、その中に入れるパラメータが多すぎて、一つ一回ずつでもかなりの手間だなと思った。何かいい方法を見つけれるといいな。


ご精読ありがとうございました。では、また次回まで✌



Day 28はこちら↓↓
programming-shop.hatenablog.com


Day 26はこちら↓↓
programming-shop.hatenablog.com

Ruby on Rails開発のインターン (Day 26)

こんにちは、皆さん!

今日のフォーカスはどうやってCapybaraテストからコントローラー内のインスタンス変数にアクセスすることができるかだ。それと、今日の朝、新たなウェブサイトのベースを作らないかと相談されたので、内容の少ない比較的新しいウェブサイトを作る機会があるかもしれない。


  • トピック:
  1. コントローラーの変数を使う代わりに
  2. ChromeのディベロッパーツールのうちのNetworkというセクションを使う


  • 疑問:


  • 問題:
  1. Capybaraテストからコントローラー内のインスタンス変数にアクセスできない(代わりの方法で解決)


  • 学習した内容:
  1. ChromeディベロッパーツールのうちのNetworkを有効に使う一つの方法


  • 今後やってみたいこと:


  • リソース:
  1. ruby on rails - 'assigns' method not found in rspec capybara - Stack Overflow


コントローラーの変数を使う代わりに

この代わりとなる方法はどこかアホっぽいけど、どりあえず、問題を解決してくれる。
僕がやったことはとても基本的なことで、テストコードを書いているファイル、つまり、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というセクションを使う

これは僕のマネージャーが見せてくれたHTTPリクエストの種類をブラウザで確認する方法

彼はChromeディベロッパーツールを開いて、Networkというセクションを開いて、Networkセクションの真下にあるPreserve logというものをクリックした。
そして、彼はウェブサイトをリロードして、そのツール上で下記のような内容のものが出てきた。

f:id:Coding_Studio:20180811081947p:plain

これはどのページがどのHTTPリクエストでプロセスされたのか教えてくれるため、エラーがどこにあるか見つけるときに役立つ。
そして、そのリンクにクリックすると、HTTPリクエストの詳細を表示してくれる。

f:id:Coding_Studio:20180811082403p:plain

これのおかげで、無事エラーがどこで発生しているかわかり、今のサイトがPOSTリクエストを出したが、失敗したのが分かった。つまり、これでこのサイトが定義されていない"/groups"というPOSTリクエストをしようとしたことが分かる。

まとめ

久しぶりに確かに何かを学んだなと感じる一日だった。Chromeディベロッパーツールを軽く掘り下げたのがきっかけに僕はもうちょっとディベロッパーツールについて学んでみたいなと思った。このトピックに関してはかなり奥深いものがあるのではないかと踏んでいる。
毎日何がしたいのかというリストなどを作り、日々しっかり管理する必要がある気がする。じゃないと、やりたいことが多すぎて、結局大事な次のものが始めれなくなっちゃう気がする。よい管理方法を見つけれるといいな。


ご精読ありがとうございました。では、また次回まで✌



Day 27はこちら↓↓
programming-shop.hatenablog.com


Day 25はこちら↓↓
programming-shop.hatenablog.com

Ruby on Rails開発のインターン (Day 25)

こんにちは、皆さん!

今日は問題なく動いているAPI キーを使う許可を取ろうと思う。そう簡単に一個くれるのかどうかはよくはわからないが。代わりの何かの手段を提案してくると予想しているが、とにかくこの問題にもうちょっとちゃんと取り組んでほしいなと思う。じゃないと、先に進めないし。


  • トピック:
  1. rails-controller-testingジェムでテスト時にコントローラー内のインスタンス変数にアクセスする


  • 疑問:


  • 問題:
  1. assign関数が使えない


  • 学習した内容:
  1. テスト時にコントローラー内のインスタンス変数を直接使うことができなく、いくつかの関数を使う必要がある


  • 今後やってみたいこと:


  • リソース:
  1. GitHub - rails/rails-controller-testing: Brings back `assigns` and `assert_template` to your Rails tests


rails-controller-testingジェムでテスト時にコントローラー内のインスタンス変数にアクセスする

Capybaraテストでコントローラー内のインスタンス変数を使いたくなる時がある。僕の場合は一つ一つのマーカーを回りたいのでそのマーカーたちが定義されているコントローラーのインスタンス変数にアクセスしたい。少なくともいくつマーカーがあるのかわかって、そしたら、マップの中心を何回動かせばいいのかわかるのでって思ったのだけど。

少しネットで探してみると、rails-controller-testingというジェムを使うべきだそう。その後、下記のようにassigns関数を使うことでインスタンス変数にアクセスするそう。

assigns(:markers)

しかしながら、これに関して、僕の場合はNo method defined assigns functionというエラーが返ってきた。よって、またこの関数について詳しく探っていかないといけないという感じだね。

まとめ

今日、ついにAPIキーの問題が解決した(しかし、いったいどこが原因でどうやって直したのかよくわからない。APIキーを変えたからかもしれない)。そして、それをクリアしたのち、初めて、Capybaraテストから直接コントローラー内のインスタンス変数にアクセスすることができないことに気づいた。明日からはこの問題について掘り下げていく。何か変数が使えるいい方法が見つかるといいな。


ご精読ありがとうございました。では、また次回まで✌



Day 26はこちら↓↓
programming-shop.hatenablog.com


Day 24はこちら↓↓
programming-shop.hatenablog.com

Ruby on Rails開発のインターン (Day 24)

こんにちは、皆さん!

今日はいろんな方法試してマップ上にマーカーを追加してみようと思う。いいの見つけれてやることリストの次のものに移れるといいな。
一方で自分のウェブサイトも作っているのでそちらも早くやりたいな。だから、仕事を早く終わらせようというモチベーションにもなっている(笑)。


  • トピック:
  1. punditジェムのインストール
  2. punditの機能を使う


  • 疑問:


  • 問題:
  1. GeocoderがAPIキーの問題があるのでデータベースにデータを追加できない


  • 学習した内容:
  1. punditジェムを使って見やすいコードのままユーザーのアクセス制限を行うことができる


  • 今後やってみたいこと:
  1. 自分のアプリでpunditジェムを使ってみる


  • リソース:
  1. GitHub - varvet/pundit: Minimal authorization through OO design and pure Ruby classes


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の機能を使う

では、実際に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キーがエラーを返してくるのか他の人たちと議論した。シニアのディベロッパーとマネージャーの2人とも彼らのテストサイトでは普通に問題なく、実行されるそうなので、ますますなぜなのかわからなくなってくる。とりあえず、この件を彼ら2人に預けて僕はもう少しコードを見回してみた。punditジェムについて学べたのはいいことだったと思う。自分のウェブサイトを作っているところだから、このアクセス制限機能をうまくアドミンユーザーのために実行できればすごく良いものが完成する気がする。
明日になってまだAPIキーの問題への解決策が見当たらなければ、彼らのキーを使わせてもらえるように呼び掛けてみようと思う。


ご精読ありがとうございました。では、また次回まで✌



Day 25はこちら↓↓
programming-shop.hatenablog.com


Day 23はこちら↓↓
programming-shop.hatenablog.com

Ruby on Rails開発のインターン (Day 23)

こんにちは、皆さん!

長い週末が終わり、また職場に戻ってきた。最近なぜかわからないが、マネージャーともう一人のディベロッパが全く連絡を取り合わないからやることリストも更新されていなくて、少し心配だ。すぐに対処してくれるといいが。


  • トピック:
  1. オートログアウトの仕組み


  • 疑問:


  • 問題:
  1. GeocoderがAPIキーの問題でデータベースにデータを足すのを拒否してくる


  • 学習した内容:
  1. Railsでオートログアウトを実行する方法


  • 今後やってみたいこと:


  • リソース:


オートログアウトの仕組み

通常セキュリティーの関係でユーザーがある程度の時間オフラインになったらアカウントからサインアウトするオートサインアウトを実行しているウェブサイトは結構ある。で、この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キーに登録しないといけないのかな?
今のところ、これへの対処法はわからないな。


ご精読ありがとうございました。では、また次回まで✌



Day 24はこちら↓↓
programming-shop.hatenablog.com


Day 22はこちら↓↓
programming-shop.hatenablog.com

Ruby on Rails開発のインターン (Day 22)

こんにちは、皆さん!

今日は同僚のインターンに来てる人が今日でラスト1日になるのでみんなとランチに行くことになっている。楽しみだな。
一方で、もうマネージャーの修正を待ってもいられないので、エラーになっている部分をコメントアウトして、自分の書いたコードをテストしていこうと思う(笑)。


  • トピック:
  1. Capybaraテストでnative関数でCSSスタイルの値をより簡単に取り出す


  • 疑問:


  • 問題:


  • 学習した内容:
  1. エラーページのレイアウトをコントロールするジェムが存在する


  • 今後やってみたいこと:


  • リソース:
  1. GitHub - charliesome/better_errors: Better error page for Rack apps


Capybaraテストでnative関数でCSSスタイルの値をより簡単に取り出す

マップのテストのため、Capybaraテストのコードを書いていたとき、下記のようなコードでCSSのwidthのハッシュを以前やったように取り出した。

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ステップを飛ばせるからコードを書くのを楽にしてくれるのだなと感じた。

まとめ

マネージャーと同僚たちとのランチはとてもよかった。レバノンのレストラン(もちろん初めて)に行ったのだが、何が有名なのか全くわからなかったわけなので、適当にオーダーした。初めてみんなとまともにしゃべるからであろう、会話はすごく充実していた。みんな生徒だったからってのもあったけど。そのうちの一人がトロント大学在学中の人だったことはそこで知った。この大学は僕がもともと行きたかった大学だった。いろいろとその大学で不便な部分が聞けて、結果的にUBCに来たのも悪くないなって思った(笑)。
仕事に関しては、エラー部分を取り除いてテストを始めた。そして、テストコード中に修正する部分があるなと思ったので、それの修正もした。そして、今週最後の日であり、3連休が待っているので、しっかり休んでまた火曜日に備えるぜ!


ご精読ありがとうございました。では、また次回まで✌



Day 23はこちら↓↓
programming-shop.hatenablog.com


Day 21はこちら↓↓
programming-shop.hatenablog.com