【未経験プログラミング】twitterクローン【xx日】

お気に入りを実装する。

 

1、likeモデル作成

2,モデルのアソシエーション、likedb作成

3,Routeing,コントローラー、view実装

 

Userは多くのお気に入りPostを持っています
Postを多くのお気に入り(By User)を持っています

 

中間テーブルを作る。

likeモデルを作成

2、モデルのアソシエーション

3つのモデルについて書きます。

like.rb

class Like < ApplicationRecord
belongs_to :user
belongs_to :micropost, class_name: 'User'
end

userとmicropostの1対多で属するので、2つ書く

 

user.rb

has_many :likes
has_many :micropostings, through: :likes, source: :micropost

 

micropostはlikeモデルを経由するのでhas_many ,thorough

イメージとしては、Userモデルのidが2番目の人のお気に入りをしているPostを取ってくる場合

Userモデル (id=2)
=> Likeモデル (user_id=2のものを探索)
=> Likeモデル (探索したものの、post_idを発見)
=> Postモデル(post_idからPostモデル内のidに変換。たどり着く)

 

 

 いつものまにかmaicropostが削除できなくなっていた。

どうやらdependent: :destroyを記入しないとmysqlからデータが削除されないらしい。

 foreign_key: 'follow_id', dependent: :destroy

 

has_many の流れをしっかり意識しないといつまでもはまる。

メソッドエラーとかあらゆるエラーを見た気がする。

 

 

 

【未経験プログラミング】twitterクローン【xx日】

https://techacademy.s3.amazonaws.com/bootcamp/laravel/twitter-clone/nvsn.png

https://techacademy.s3.amazonaws.com/bootcamp/laravel/twitter-clone/nvsn0.png

Userを表す user_id とフォローされる側のUserを表す follow_id のカラムを持たせます。

→micropost_ID = follow_id

rails g model Like user:references micropost:references

 

has_many :reverses_of_like, class_name: 'Like', foreign_key: 'micropost_id'
has_many :microposts, through: :reverses_of_like, source: :user

いらないとの事。

UserとUserの双方向で関連付けはいらない

そのため、双方向を意識するなら、 `models/microport.rb` に2行の関連付けが必要です。
ただ課題の要件上は、Microportモデル側の関連付けは使いません。
そこで今回は `models/user.rb` に適切な2行の関連付けがあれば良いですね。

 

エラー

undefined local variable or method `user' for 

user idから current_user.Idに2箇所変更

<% if current_user.microposting?(current_user) %>

<%= hidden_field_tag :micropost_id, current_user.id %>

 

gyazo.com

NoMethodError in Users#likes

undefined method 'name' for nil:Nilclass

→ネームメソッドない

 

実装されていなくても表示される。TOP画面等

Users/likes.html.erb

users_controller

定義なしの為nilで帰ってきた。

 

def likes

@user = User.find(params[:id])
@microposts = @user.microposts.page(params[:page])

 

 

【未経験プログラミング】twitterクローン【40日】

gyazo.com

NoMethodError in Users#likes

undefined method 'name' for nil:Nilclass

→ネームメソッドない

 

実装されていなくても表示される。TOP画面等

Users/likes.html.erb

users_controller

定義なしの為nilで帰ってきた。

 

def likes

@user = User.find(params[:id])
@microposts = @user.microposts.page(params[:page])

 

 

 

 

 

【未経験プログラミング】twitterお気に入り実装【42日-2】

①中間テーブルを作る。

$ rails g model Like user:references micropost:references

 

user_idとtweet_idで重複し保存しないように

t.index [:user_id, :micropost_id], unique: true

 

.自動生成された

app/models/relationship.rbを変更

class Favorite < ApplicationRecord
belongs_to :user
belongs_to :tweet,class_name: 'User'

validates :user_id, presence: true
validates :micropost_id, presence: true

end

 

migrate

  • t.references :user, foreign_key: true
    • 実際のデータベース上では、user_idカラムとして存在しています
  • t.references :micropost, foreign_key: true
    • 実際のデータベース上では、micropost_idカラムとして存在していま

class CreateLikes < ActiveRecord::Migration[5.0]
def change
create_table :likes do |t|
t.references :user, foreign_key: true
t.references :micropost, foreign_key: true

t.timestamps
end

 

 

 

 

【未経験プログラミング】twitterクローン多対多【42日】

ModelとModelの関係(リレーション)の種類は『一対多』だけでなく、『多対多』という関係

 

中間テーブルが必要

belongs_to と has_many のメソッドによって両者の関係をモデルファイルに記述することで関係を定義し、 user.microposts や micropost.user が使用可能になった

 

①中間テーブルを作る

rails g model Relationship user:references follow:references 

t.references :follow, foreign_key: { to_table: :users } の { to_table: :users } というオプションによって、外部キーとしてusersテーブルを参照するという指定を行っています。

また t.index [:user_id, :follow_id], unique: true という記述も追加しています。
これは user_id と follow_id のペアで重複するものが保存されないようにするデータベースの設定です。

rails db:migrate

rails db:migrate:status

エラーでました。

 t.references :follow, foreign_key: true
t.references :follow, foreign_key: { to_table: :users }

に変更忘れでした。

Mysql2::Error: Can't create table テーブルエラーでした。Syntax Errorだったら別の原因を探す。

 

外部キーとしてuserテーブルを参照するって↑に書いてるのに忘れるとは・・・。

 

app/models/relationship.rb

命名規則を変更しているフォローについて補足する。

belongs_to :follow から
belongs_to :follow, class_name: 'User'

関連モデルでの追加

バリテーション(共通化

app/models/user.rb

has_many に追加

has_many :relationships
順方向:has_many :followings, through: :relationships, source: :follow
逆方向has_many :reverses_of_relationship, class_name: 'Relationship', foreign_key: 'follow_id'
逆方向:has_many :followers, through: :reverses_of_relationship, source: :user

ここで思い出して欲しいのは、『多対多』の関係は2つの『一対多』の関係の組み合わせだと言うことです。

has_manyメソッド

一対多の関係とは、ある1つの Model インスタンス(A)に対して、複数の Model インスタンス(B, B, …)を保持する関係のことです。例えば、今回の User と Micropost では、1人の User は複数の Micropost をツイート(has_many)することが可能であり、 Micropost は 必ず1人の User に所属(belongs_to)することが決まっています。

 

has_many:relationships:多対多 の多の部分 ※犬猫など

has_many :reverses_of_relationship, class_name: 'Relationship', foreign_key: 'follow_id'

has_many :relationships の逆方向(reverse)です。

:reverses_of_relationship は筆者が命名したものなので、class_name: 'Relationship' で参照するクラスを指定しています。
また、Rails命名規則により、User から Relationship を取得するとき、user_id が使用されます。
そのため、逆方向では、foreign_key: 'follow_id' と指定して、 user_id 側ではないことを明示します。

これらのオプションは、順方向であった has_many :relationships では必要ありませんでしたが、Rails命名規則に沿っていない逆方向では必要なオプションです。

 

ここまでの内容で気をつけることは、 has_many :relationships などの書き方は、あくまでRelationshipモデルへの参照であるということです。つまりUserから見た中間テーブルとの関係になります。

 

この人がフォローしているの人は誰か?という処理をコードなしに実装しているのが

user.followings と書けば、該当の user がフォローしている User 達を取得できるようにします。

その機能を提供するのが has_many ..., through: ... です

has_many :followings, through: :relationships, source: :follow # <= この行
  has_many :followers, through: :reverses_of_relationship, source: :user 

の2行。

has_many :followings, through: :relationships, source: :follow の場合、まず、has_many :followings という関係を新しく命名して『フォローしているUser達』を表現しています。

through: :relationships という記述により、has_many: relationships の結果を中間テーブルとして指定しています。

その中間テーブルのカラムの中でどれを参照先の id とすべきかを source: :follow で、選択しています。

結果として、user.followings というメソッドを用いると、 user が中間テーブル relationships を取得し、その1つ1つの relationship の follow_id から 自分フォローしている User 達 を取得するという処理が可能になります。
中間テーブルを経由して相手の情報を取得できるようにするためには throught を使用すると覚えておきましょう。

 

https://techacademy.s3.amazonaws.com/bootcamp/webapp/twitter-clone/has_many_through_rails.png

今度は 自分フォローしている User 達 を取得します。

has_many :followers, through: :reverses_of_relationship, source: :user も、順方向に対して、逆の設定をしているだけです。through: には逆方向の :reverses_of_relationship を指定しており、 source: :user で relationships 中間テーブルの user_id のほうが取得したい User だと指定しています。これで、user.followers によって、「自分をフォローしている User 達」を取得することができます。

https://techacademy.s3.amazonaws.com/bootcamp/webapp/twitter-clone/has_many_through_r_rails.png

次にこのフォローの関係を手軽に作成したり外したり出来るように、Userモデルにメソッドを追加していきましょう。
メソッドの使用イメージは特定のUserが user.follow(other_user) や、 user.unfollow(other_user) として、該当のUserをフォロー/アンフォローできるようにするというものです。
また、既にフォローしているかどうかも分かるように following? メソッドも作成しておきます。

フォロー/アンフォローは中間テーブルのレコードを保存/削除にあたる

 

def follow(other_user)

  unless self == other_user
self.relationships.find_or_create_by(follow_id: other_user.id)

unless self == other_user によって、フォローしようとしている other_user が自分自身ではないかを検証しています。

self.relationships.find_or_create_by(follow_id: other_user.id) は、見つかれば Relation を返し、見つからなければ self.relationships.create(follow_id: other_user.id) としてフォロー関係を保存(create = build + save)することができます。これにより、既にフォローされている場合にフォローが重複して保存されることがなくなります。

selfはをメソッドの中で呼び出すとオブジェクトを見ている。

 

def unfollow(other_user)

relationship = self.relationships.find_by(follow_id: other_user.id)
relationship.destroy if relationship

フォローがあればアンフォローしています。また、relationship.destroy if relationship は、relationship が存在すれば destroy します。if文はこのように書けます。

 

def following?(other_user) 

self.followings.include?(other_user)

self.followings によりフォローしている User 達を取得し、include?(other_user) によって other_user が含まれていないかを確認しています。含まれている場合には、true を返し、含まれていない場合には、false を返します。

> user1.follow(user2)   # user1がuser2をフォローする
> user1.reload          # user1を再取得
> user1.followings      # user1のフォローしている人たちを取得

また、 reload メソッドを入れたのは、 user1 のインスタンスを再取得するためです。

理由をみていきます。
user1.follow(user2) をすると、データベースは更新され、フォローしたことになります。
しかし、 user1.followings を実行してもまだ user2 が followings に出てきません。
理由は、 user1.follow(user2) しても、user1 にその結果が反映されないからです。
そのため、もう一度 user1 = User.first などとして更新した状態のレコードを再取得する必要があります。その代わりに、reload とすれば、自動的にインスタンス(レコード)を再取得してくれます。

 

config/routes.rb

Rails.application.routes.draw do
  root to: 'toppages#index'

  get 'login', to: 'sessions#new'
  post 'login', to: 'sessions#create'
  delete 'logout', to: 'sessions#destroy'

  get 'signup', to: 'users#new'
  resources :users, only: [:index, :show, :new, :create] do
    member do
      get :followings
      get :followers
    end
  end

  resources :microposts, only: [:create, :destroy]
  resources :relationships, only: [:create, :destroy]
end

ログインユーザがユーザをフォロー/アンフォローできるようにするルーティングは、 resources :relationships, only: [:create, :destroy] 

保存/削除

Relationship は中間テーブルなので index や show でユーザに見せるようなリソースではありません。フォロー/アンフォローボタンは View で設置します。

フォロー中のユーザとフォローされているユーザ一覧を表示するページは必要です。そのためのルーティングが下記コードになります。member do ... end が追加されています。

Prefix Verb                 URI Pattern               Controller#Action

followings_user GET /users/:id/followings(.:format) users#followings
followers_user GET /users/:id/followers(.:format) users#followers

 

resources には member と collection という URL を深掘りするオプションを付与することができます。

collection do
get :search
end

collection は member と違って、/users/search のように :id が含まれない URL を生成します。大きな違いは、ユーザを :id によって特定する必要があるページかどうかで member か collection かを選択します。今回のように、ユーザの検索結果を表示する /users/search の場合、ユーザを特定してしまっては検索の意味がないので、:id は不要です。そのため、collection を使用します。

 

 app/controllers/application_controller.rb

  def counts(user)
    @count_microposts = user.microposts.count
    @count_followings = user.followings.count
    @count_followers = user.followers.count
  end

 これでカウントの保存ができるようになる。

app/views/users/show.html.erb 実装画面

 <li class="<%= 'active' if current_page?(user_path(@user)) %>"><%= link_to user_path(@user) do %>Microposts <span class="badge"><%= @count_microposts %></span><% end %></li>

フォローボタン実装

app/views/relationships/_follow_button.html.erb

    <%= form_for(current_user.relationships.build) do |f| %>
      <%= hidden_field_tag :follow_id, user.id %>
      <%= f.submit 'Follow', class: 'btn btn-primary btn-block' %>
    <% end %>

上記がフォローボタンになる。

<%= hidden_field_tag :follow_id, user.id %> は、<input type="hidden" name="follow_id" value="ユーザの id">を生成します。

type="hidden" はユーザに見せないフォームの隠しデータとなります。relationships#create にフォームデータが送信されたとき、フォローすべきユーザの user.id を知りたいのですが、このように hidden として送信する以外に user.id を手に入れる方法がありませんので、このようにしています。Controller 側では params[:follow_id] として取得します。

 

タイムラインの実装

def feed_microposts

.where(user_id: self.following_ids + [self.id])

 

Controller

@microposts = current_user.microposts.order('created_at DESC').page(params[:page])

@microposts = current_user.feed_microposts.order('created_at DESC').page(params[:page])

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

【未経験プログラミング】twitterクローン【41日】

おそらくgitcloneを行った関係で pushができなくなりました。

https://i.gyazo.com/29f9d5655cb512742a0e4b193d3c025c.png

存在しないtasklistsテーブルにuser_idカラムを追加する命令になっているようです。

作成したマイグレーションファイルの記述内容が間違っているので、そちらを確認してみてください

マイグレーションファイルが無駄にできていた。

rails db:migrate:statusで確認

downを手動削除

rails db:migrate`

無事起動。

 

https://gyazo.com/b7f65ba29b2894e2c688750c560c168f

そのエラーは、`logged_id?`というメソッドが定義されていないことが原因だと思いますので、定義されているか確認してみてください。

app/helpers/sessions_helper.rb

module SessionsHelper
def current_user
@current_user ||= User.find_by(id: session[:user_id])
end

def logged_in?
!!current_user
end
end

としてるのですが、間違いでしょうか?

mentor-kawaguchi [18:33]
そこまではOKです!
controllerでのincludeが漏れているのではないでしょうか?

 

アンサー:漏れていましたorz

 


https://i.gyazo.com/9c47978861425d551c721f8546211ad8.png

エラー部分で不自然に空白があるのが確認できます。
このような場合は全角スペースが紛れているので、削除してみてください。
Usersコントローラの記述ですね
全角スペースを見つけるには、探したいファイルを開いた状態で、キーボードで「command + F(Windowsの場合、Ctrl + F)」を押してください。

そうすると、検索窓が表示されます。
そこで、全角スペースを入力してください。もしあれば数字で表示されます。またその場所も表示されます。

そして検索窓を隠すにはescキーです

 

→全角2箇所ありましたとさ。。。。。削除して無事起動

 

タスクの投稿のstatusがWebアプリケーション上で受け取ってくれません。
https://gyazo.com/e3f944622e507d924825540a915e406f

railsコンソールでは
task = user.tasks.build(content: 'hello', status: 'hello2' )
で保存できるのですが教えて頂けますか?

 

A:そうしたらビュー側のフォーム部分の記述の確認とコントローラー側のストロングパラメータの2箇所を確認してみてください

まずその表示でも「タイトル」となっているのが不自然ですが、その入力欄の生成部分の確認です

 

params.require(:task).permit(:content, :user_id)

上記の記述削除で無事起動

 

https://gyazo.com/f0b4b58a44a1fcc0814a1e6140f06125

と出たので
def show
@task = current_user.tasks.find(params[:id])
end

を追記したところ
https://gyazo.com/2b8038df90f1bed530d17a7d8a0059a4

と出ます。次はどこを確認するべきでしょうか?

 

ID29のレコードがないといわれていますね。
これはどのような操作をした際にでるエラーでしょうか?
削除した際に出るのでしたら削除後のリダイレクト先をTOPページにするなどすると良いと思います。

 

A:def destroy部分の
redirect_back(fallback_location: root_path)
から
redirect_to tasks_url
に変更したらうまくいきました。

 

------------------------------ここから地獄の10時間オーバー

git checkout  ハッシュ値で 呼び出し 課題取り組んでいました。
git push origin master で反映できないので
課題完了後に git checkout master に変更したところ
データがロールバックしたのですが戻す方法はあるのでしょうか?

 

ごめんなさい。どのような状況で git checkout master を行いましたか?
 git checkout master を行う前の状態をコミットしていますか?

 

ターミナルのログが消えてしまい正確には言えないのですが
detached HEADがでたので git checkout master行いました

行う前にコミットはしましたcommitはしました。

 

ログを確認して `git reset --hard リビジョン番号` で戻せませんでしょうか?

https://gyazo.com/f2c86c0bb120eca3695e593dd131c721

さらに

rails db:migrate:resetを行い戻りました。

 

動作はうまくいくようになったのですが、下記のようにでます。
rm -rf .git/ でいいのでしょうか?

https://gyazo.com/a50c85c8afc871d6373c3af9874968b7

 

それをやるとリポジトリ削除をすることになりますが、削除したいのでしょうか?今までのgit履歴が全て無くなってしまい復元できなくなってしまいます。

あ。見たところ不要なものを参照しているようですね。
これはenvironment直下にあるリポジトリが原因かなと思います。
これは不要なので削除した方が良いです。

 

rm -rf ~/environment/.git

→fatal: pathspec '/home/ec2-user/environment/.git' did not match any files

 

メンターの方は問題ないそうです
https://i.gyazo.com/c33a37c0da402ff52c9027f50eb4c106.png

 

⑧git rm --cached kadai-tasklist

git add . はうまくいきました。
git commit -m "xxx"
git push origin master

ec2-user:~/environment/kadai-tasklist (master) $ git push origin master
fatal: 'origin' does not appear to be a git repository
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

アクセス権がないと?
git push -f origin master を行っていいのでしょうか?

 

ここでメンターさん時間になり別のかたに交代

 

A:リモートレポジトリの登録が行なわれていないようですね。
`git remote add orign <リモートレポジトリ>` のようにして、リモートレポジトリの登録をしてあげる必要があります。

リモートレポジトリが登録できているかの確認は、 `git remote -v` でしてみてください。
何も表示されなければ、リモートレポジトリが登録されていないということになります。

→何も表示されない。

 

A:リモートレポジトリの登録をしてあげてください。

 

登録時にSSHで登録してしまっていた

HTTPSで登録しないと下記エラーがでる。

https://gyazo.com/1e9fbc56632a606953bdfe0347ef7302

 

pushした時にURLとパスワードを求められるようにあったのですが、
下記の通りマージエラーがでます。

 

A:リモートレポジトリの変更はきちんとできたみたいですね。

ローカルの方が正しければ、 `git push origin master -f` として、強制的にローカルからの push で上書きできますので試してみてください。

 

⑨herokuにデプロイしうと思ったら上記どうようのエラー

 

`git push origin heroku -f` としてみて上手くいけば問題ないです。
もし駄目でしたら、 heroku アプリの登録からやりなおしてみた方が良いかもしれませんね。

 

当然のように駄目でした

 

以上、です。

 

 

 

 

 

 

 

 

 

【未経験プログラミング】twitterクローン【40日】

current_user.tasks.build

 

@task = current_user.tasks.find

ログインしているユーザーのタスクを探す

 

db status down up を確認する、downだとマイグレーションできていない。手動削除可能。

マイグレーションしたファイルにはカラム追加を使う、直接編集は不可

存在しないtasklistsテーブルにuser_idカラムを追加する命令になっているようです。
作成したマイグレーションファイルの記述内容が間違っているので、そちらを確認してみてください

 

メソッドに定義されていないパターンが多い

そのエラーは、`logged_id?`というメソッドが定義されていないことが原因だと思いますので、定義されているか確認してみてください。