ぞえの技術めも

Ruby on Rails勉強中

【167日目】【1日20分のRailsチュートリアル】【第12章】relationshipsテーブルを作成する

Ruby on Railsチュートリアル(第3版)

今日は「12.1.1 データモデルの問題 (および解決策)」から。

12.1.1 データモデルの問題 (および解決策)

ユーザーをフォローするデータモデル構成のための第一歩として、典型的な場合を検討してみましょう。

まず名前付けとして、
* あるユーザーがフォローしているすべてのユーザーの集合→following * あるユーザーがフォローされているすべてのユーザーの集合→followers とするらしい。
うーん、ややこしい。英語って難しい。とりあえずTwitterと一緒にしたのね…。

能動的関係も受動的関係も、最終的にはデータベースの同じテーブルを使うことになります。したがって、テーブル名にはこの「関係」を表す「relationship」を使いましょう。モデル名も同様にして、Relationshipモデルとします。作成したRelationshipデータモデルを図12.8に示します。

なんやかんやあって図12.8の形に落ち着いた、と。

このデータモデルを実装するために、まずは次のように図12.8に対応したマイグレーションを生成します。

マイグレーション生成しましょう。

$ rails generate model Relationship follower_id:integer followed_id:integer
  :
      invoke  active_record
      create    db/migrate/20170726030438_create_relationships.rb
      create    app/models/relationship.rb
      invoke    test_unit
      create      test/models/relationship_test.rb
      create      test/fixtures/relationships.yml

このリレーションシップは今後follower_idとfollowed_idで頻繁に検索することになるので、リスト12.1に示したように、それぞれのカラムにインデックスを追加します。

db/migrate/[timestamp]_create_relationships.rb

    add_index :relationships, :follower_id
    add_index :relationships, :followed_id
    add_index :relationships, [:follower_id, :followed_id], unique: true

リスト12.1では複合キーインデックスという行もあることに注目してください。これは、follower_idとfollowed_idの組み合わせが必ずユニークであることを保証する仕組みです。これにより、あるユーザーが同じユーザーを2回以上フォローすることを防ぎます。

なるほど、確かにあるユーザーが同じユーザーを2回以上フォローすることはないもんね。

ふと気になったけど、フォロー解除したときはレコード消すのかな…?今後出てくるの待とう。

relationshipsテーブルを作成するために、いつものようにデータベースのマイグレーションを行います。

relationshipsテーブル作成できましたー。

$ bundle exec rake db:migrate
== 20170726030438 CreateRelationships: migrating ==============================
-- create_table(:relationships)
   -> 0.0016s
-- add_index(:relationships, :follower_id)
   -> 0.0009s
-- add_index(:relationships, :followed_id)
   -> 0.0010s
-- add_index(:relationships, [:follower_id, :followed_id], {:unique=>true})
   -> 0.0135s
== 20170726030438 CreateRelationships: migrated (0.0173s) =====================

今日の学習時間は【26分】

次は「12.1.2 User/Relationshipの関連付け」から。

【167日目】【1日20分のRailsチュートリアル】【第12章】第12章向けのブランチを作成する

Ruby on Railsチュートリアル(第3版)

今日は「第12章 ユーザーをフォローする」から。

第12章 ユーザーをフォローする

この章では、他のユーザーをフォロー (およびフォロー解除) できるソーシャルレイヤーを追加し、各ユーザーのHomeページに、現在フォロー中のユーザーのステータスフィードを表示できるようにして、サンプルアプリケーションのコアを完成させます。

うーん、難しそう。ゆっくり順を追って勉強していくか。。。

12.1 Relationshipモデル

ユーザーをフォローする機能を実装する第一歩は、データモデルを構成することです。ただし、これは見た目ほど単純ではありません。
(中略)
これを解決するためのhas_many through (多対多の関係を表すのに使用) についてもこの後で説明します。

ユーザーをフォローする機能は多対多の関係を使うのか。

Gitユーザーはこれまで同様新しいトピックブランチを作成してください。

新しいブランチ作る前に第11章の演習内容をコミットしておこう。
これしておかないと演習の内容が次の章のブランチでコミットするときに入っちゃうことに最後になって気づいた…今まで忘れてたから微妙に入ってる気がする。。。

$ git add -A
$ git commit -m "Add user microposts exercises"

よし、第12章用のブランチ作ろう。

$ git checkout master
$ git checkout -b following-users

$ git statusで演習の内容が残ってないことも確認。これでばっちり!

ブランチ作ったところで今日はここまで。

今日の学習時間は【20分】

次は「12.1.1 データモデルの問題 (および解決策)」から。

【166日目】【1日20分のRailsチュートリアル】【第11章】演習の3.

Ruby on Railsチュートリアル(第3版)

今日は「11.6 演習」の3.から。

11.6 演習

3.リスト11.69に示すテンプレートを参考に、11.4で実装した画像アップローダーをテストしてください。テストの準備として、まずはサンプル画像をfixtureディレクトリに追加してください (コマンド例: “cp app/assets/images/rails.png test/fixtures/”)。
(省略)

問題文面が長い…!

まずサンプル画像をfixtureディレクトリに追加する。

$ cp app/assets/images/rails.png test/fixtures/

紛らわしいエラーを回避するためには、CarrierWaveの設定を変更し、テスト環境では画像リサイズをしないようにする必要があるので、リスト11.70に示す設定ファイルを使ってください。

紛らわしいエラーって何のことなんだろう…。
とりあえずテスト環境では画像リサイズしないようにする。

$ touch config/initializers/skip_image_resizing.rbでファイルを生成して下記のように更新。

config/initializers/skip_image_resizing.rb

if Rails.env.test?
  CarrierWave.configure do |config|
    config.enable_processing = false
  end
end

いよいよテスト作成かな。テンプレートを参考に穴埋めしてみた。

test/integration/microposts_interface_test.rb

  test "micropost interface" do
    :
    assert_select 'input[type=file]'
    :
    # 有効な送信
    content = "This micropost really ties the room together"
    picture = fixture_file_upload('test/fixtures/rails.png', 'image/png')
    assert_difference 'Micropost.count', 1 do
      # post microposts_path, micropost: { content: content }
      post microposts_path, micropost: { content: content, picture: picture }
    end
    assert assigns(:micropost).picture?
    :

合ってるか分からないけどテストは通った。のでよしとしよう。。。。

$ bundle exec rake test
60 tests, 314 assertions, 0 failures, 0 errors, 0 skips

今日の学習時間は【23分】

次は「第12章 ユーザーをフォローする」から。いよいよ最後の章だー!

【165日目】【1日20分のRailsチュートリアル】【第11章】演習の2.

Ruby on Railsチュートリアル(第3版)

今日は「11.6 演習」の2.から。

11.6 演習

2.サイドバーにあるマイクロポストの合計投稿数をテストしてください。このとき、単数形 (micropost) と複数形 (microposts) が正しく表示されているかどうかもテストしてください。(リスト11.68を参考にしてみてください)

マイクロポスト投稿数が1のときは単数形 (micropost) になるんだっけ…。

@user.microposts.count'Micropost.count'の使い分けがよく分かってないことに気づいた。 'Micropost.count'ってなんだ……
使えるケースが限られてるのかな。

test/integration/microposts_interface_test.rb

  test "micropost sidebar count" do
    log_in_as(@user)
    get root_path
    assert_match "#{@user.microposts.count} microposts", response.body
    # まだマイクロポストを投稿していないユーザー
    other_user = users(:mallory)
    log_in_as(other_user)
    get root_path
    assert_match "0 microposts", response.body
    other_user.microposts.create!(content: "A micropost")
    get root_path
    assert_match "1 micropost", response.body
  end

とりあえずテストは通りました。

$ bundle exec rake test
60 tests, 312 assertions, 0 failures, 0 errors, 0 skips

今日の学習時間は【22分】

次は「11.6 演習」の3.から。

【164日目】【1日20分のRailsチュートリアル】【第11章】演習の1.

Ruby on Railsチュートリアル(第3版)

今日は「11.6 演習」から。

11.6 演習

なお、演習とチュートリアル本編の食い違いを避ける方法については、演習用のトピックブランチに追加したメモ (3.6) を参考にしてください。

演習用にブランチ切っておきましょう。

$ git checkout user-microposts
$ git checkout -b user-microposts-exercises

1.if-else文の2つの分岐に対して、それぞれ異なるパーシャルを使用するようにHomeページをリファクタリングしてください。

ノーヒント…!!

11.3.2 マイクロポストを作成する」にちらっと書かれてる下記のことか。

if-else分岐を使用してコードを書き分けている点が少し汚いですが、このコードのクリーンアップは演習に回すことにします (11.6)。

Homeページのif-else文ていうのはユーザーがログインしているかどうかのif-else文。 ユーザーがログインしていればユーザー情報やマイクロポストの表示をするけど、ログインしていなければサインアップを促す内容を表示する。

それぞれの内容をパーシャル化するとして、ユーザーログインに関するif文はどこに持ってけばいいのかな…。パーシャルの方でいいのかな。

まずパーシャル用のファイルを作成して、(ファイル名が微妙なのは気にしてはいけない)

$ touch app/views/shared/_home_logged_in.html.erb
$ touch app/views/shared/_home_welcome.html.erb

if-else分岐の内容をとりあえずコピペ。if文も持ってきてみたよ。

app/views/shared/_home_logged_in.html.erb

<% if logged_in? %>
  <div class="row">
    <aside class="col-md-4">
      <section class="user_info">
        <%= render 'shared/user_info' %>
      </section>
      <section class="micropost_form">
        <%= render 'shared/micropost_form' %>
      </section>
    </aside>
    <div class="col-md-8">
      <h3>Micropost Feed</h3>
      <%= render 'shared/feed' %>
    </div>
  </div>
<% end %>

app/views/shared/_home_welcome.html.erb

<% if !logged_in? %>
  <div class="center jumbotron">
    <h1>Welcome to the Sample App</h1>
  
    <h2>
      This is the home page for the
      <a href="http://www.railstutorial.org/">Ruby on Rails Tutorial</a>
      sample application.
    </h2>
  
    <%= link_to "Sign up now!", signup_path, class: "btn btn-lg btn-primary" %>
  </div>
  
  <%= link_to image_tag("rails.png", alt: "Rails logo"),
              'http://rubyonrails.org/' %>
<% end %>

そして作成したパーシャルを使ってHomeページのビューを更新。わー、シンプル。

app/views/static_pages/home.html.erb

<%= render 'shared/home_logged_in' %>
<%= render 'shared/home_welcome' %>

これでいいのかな…。テストはとりあえず通った。

$ bundle exec rake test
59 tests, 306 assertions, 0 failures, 0 errors, 0 skips

心配なので実動作も見てみたけどとりあえず問題なさそう…??

↓ログイン済みの場合

f:id:kt_zoe:20170718123547p:plain

↓ログインしてない場合

f:id:kt_zoe:20170718123602p:plain

合ってるかは分からないけどシンプルにはなったので良しとしよう。

今日の学習時間は【29分】

次は「11.6 演習」の2.から。

【163日目】【1日20分のRailsチュートリアル】【第11章】第11章のまとめ

Ruby on Railsチュートリアル(第3版)

今日は「11.5 最後に」から。

11.5 最後に

Micropostsリソースの追加によって、サンプルアプリケーションはほぼ完成に近づきました。残すところは、ユーザーをお互いにフォローするソーシャルな仕組みのみとなります。

ほぅほぅ、後はお互いにフォローする仕組みか…!

もし11.4.4をスキップしていたら、ここで今までの変更のコミットとmergeを済ませてください。

スキップしてるのでコミットとマージを済ませよう。

$ bundle exec rake test
59 tests, 306 assertions, 0 failures, 0 errors, 0 skips
$ git add -A
$ git commit -m "Add user microposts"
$ git checkout master
$ git merge user-microposts
$ git push

リモートリポジトリにもpushできてますね。

f:id:kt_zoe:20170713123425p:plain

準備ができたら、本番環境へデプロイしてみましょう。

本番環境へのデプロイはいいか…メールのとこからやってないし。。。

なお、必要なgemはここまでですべてインストールしたので、今後の章では新たなgemは追加しません。参考までに、最終状態のGemfileをリスト11.67に示します。

試しに比較してみたらfogのバージョンが私の環境では1.36.0になってた。(チュートリアルは`1.26.0)
んー、、、まぁいっか。

11.5.1 本章のまとめ

見返すと色々やったんだな…。全部理解できているかと言えば怪しいけど。。。

CarrierWaveを使うと画像アップロードや画像リサイズができる

個人的にはこれびっくりだった。簡単すぎる~

今日の学習時間は【16分】

次は「11.6 演習」から。

【162日目】【1日20分のRailsチュートリアル】【第11章】アップロード時に画像のリサイズを実施する

Ruby on Railsチュートリアル(第3版)

今日は「11.4.3 画像のリサイズ」から。

11.4.3 画像のリサイズ

ファイルサイズに対するバリデーション (11.4.2) はうまくいきましたが、画像サイズ (縦横の長さ) に対する制限はないので、大きすぎる画像サイズがアップロードされると図11.21のようにレイアウトが壊れてしまいます。

そうそう、レイアウトが崩れちゃうんですよね~。(実践済み)

画像をリサイズするためには、画像を操作するプログラムが必要になります。今回はImageMagickというプログラムを使うので、これを開発環境にインストールしておく必要になります。 Cloud IDEでは下記コマンドでImageMagickをインストール。

インストール途中で続けていいか聞かれるのでYを入力。

$ sudo apt-get update
$ sudo apt-get install imagemagick --fix-missing

次に、MiniMagickというgemを使って、CarrierWaveからImageMagickを使えるようにします。

元々生成されてたinclude文をコメントアウトして、縦横どちらかが400pxを超えていた場合、適切なサイズに縮小するオプションを追加。
これだけでリサイズできちゃうの…?

app/uploaders/picture_uploader.rb

  :
  # Include RMagick or MiniMagick support:
  # include CarrierWave::RMagick
  include CarrierWave::MiniMagick
  process resize_to_limit: [400, 400]
  :

気になるので動作見てみよう。

サーバーを起動して

$ rails server -b $IP -p $PORT

前と同じ画像をアップロードしてみる。

f:id:kt_zoe:20170712123425p:plain

わー!リサイズできてる!!いい感じ!

画像のアップロード時にリサイズするのですでにアップロードしてるやつには適用されないよう。残念なままで残しておくか。。。。

今日の学習時間は【22分】

次は「11.4.4 本番環境での画像アップロード」、、、と見せかけて、本番環境はそもそもアカウント登録できない(メール機能追加してない)のでこの項はスルーかな。
また本番環境作りたい!と思ったときにでも読みます。

というわけで次は「11.5 最後に」から。いよいよ第11章も終わりが近づいてきた…!