【169日目】【1日20分のRailsチュートリアル】【第12章】Relationshipモデルのバリデーションを追加する
今日は「12.1.3 Relationshipのバリデーション」から。
12.1.3 Relationshipのバリデーション
先に進む前に、Relationshipモデルの検証を追加して完全なものにしておきましょう。
Relationshipモデルのバリデーションのテストとバリデーション自体を追加する。
follower
、followed
に対してidがnilの場合はRelationshipが有効じゃないことを確認する、って感じなのかな…??
test/models/relationship_test.rb
require 'test_helper' class RelationshipTest < ActiveSupport::TestCase def setup @relationship = Relationship.new(follower_id: 1, followed_id: 2) end test "should be valid" do assert @relationship.valid? end test "should require a follower_id" do @relationship.follower_id = nil assert_not @relationship.valid? end test "should require a followed_id" do @relationship.followed_id = nil assert_not @relationship.valid? end end
app/models/relationship.rb
validates :follower_id, presence: true validates :followed_id, presence: true
ユーザーのときと同じで (リスト6.30でfixtureの内容を削除したように)、今の時点では生成されたリレーションシップ用のfixtureファイルも空にしておきましょう (リスト12.6)。
ユーザーのときのこと覚えてないけど今は空にしておきましょう。
test/fixtures/relationships.yml
# empty
これでテストが通るようになりました。
$ bundle exec rake test 62 tests, 309 assertions, 0 failures, 0 errors, 0 skips
今日の学習時間は【12分】。
次は「12.1.4 フォローしているユーザー」から。
【168日目】【1日20分のRailsチュートリアル】【第12章】UserモデルとRelationshipモデルの関連付け
今日は「12.1.2 User/Relationshipの関連付け」から。
12.1.2 User/Relationshipの関連付け
フォローしているユーザーとフォロワーを実装する前に、UserとRelationshipの関連付けを行います。
1人のユーザーにはhas_many (1対多) のリレーションシップがあり、このリレーションシップは2人のユーザーの間の関係なので、フォローしているユーザーとフォロワーの両方に属します (belongs_to)。
うーん、よく分からない…。active_relationships
のactive
ってどこから来たんや…。relationships
じゃ駄目なの…??
Micropostと似たような実装にはなるけど、そのままそっくりでは駄目で、クラス名を明示してあげる必要があるのは分かった。
先ほどの説明をコードにまとめると、UserとRelationshipの関連付けはリスト12.2とリスト12.3のようになります。
ふむふむ、Relationshipモデル内にはユーザーIDと関連付ける属性が2つあるので、それぞれ別の名前付けないとね、ってことか。
で、設計時点でfollower
とfollowed
を用意しているのでそれぞれどっちもUserモデルと関連してるよ、って明示しないといけないのかー。
app/models/user.rb
: has_many :active_relationships, class_name: "Relationship", foreign_key: "follower_id", dependent: :destroy :
app/models/relationship.rb
class Relationship < ActiveRecord::Base belongs_to :follower, class_name: "User" belongs_to :followed, class_name: "User" end
(ユーザーを削除したら、ユーザーのリレーションシップも同時に削除される必要があります。そのため、関連付けにdependent: :destroyも追加しています。)
なるほど。便利だなぁ。
今日の学習時間は【23分】。
次は「12.1.3 Relationshipのバリデーション」から。
【167日目】【1日20分のRailsチュートリアル】【第12章】relationshipsテーブルを作成する
今日は「12.1.1 データモデルの問題 (および解決策)」から。
12.1.1 データモデルの問題 (および解決策)
ユーザーをフォローするデータモデル構成のための第一歩として、典型的な場合を検討してみましょう。
まず名前付けとして、
* あるユーザーがフォローしているすべてのユーザーの集合→following
* あるユーザーがフォローされているすべてのユーザーの集合→followers
とするらしい。
うーん、ややこしい。英語って難しい。とりあえずTwitterと一緒にしたのね…。
能動的関係も受動的関係も、最終的にはデータベースの同じテーブルを使うことになります。したがって、テーブル名にはこの「関係」を表す「relationship」を使いましょう。モデル名も同様にして、Relationshipモデルとします。作成したRelationshipデータモデルを図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章向けのブランチを作成する
今日は「第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.
今日は「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.
今日は「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.
今日は「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
心配なので実動作も見てみたけどとりあえず問題なさそう…??
↓ログイン済みの場合
↓ログインしてない場合
合ってるかは分からないけどシンプルにはなったので良しとしよう。
今日の学習時間は【29分】。
次は「11.6 演習」の2.から。