Rails-Twitter


![](http://findicons.com/files/icons/1607/ruby_on_rails/128/ror_logo.png)

### View
全体で使用するHTMLのレイアウト`app/views/layouts/application.html.erb`
`<%= yield %>`に各ページのテンプレート（erbファイル）が読み込まれる
`/public/fabicon.ico`設定

### Controller
`rails generate controller static_pages home`

### Model
`rails generate model User name email password_digest`
ユニークインデックスを追加
`t.index :email, unique: true`

## ユーザーの新規登録機能

### Controller
`rails generate controller users new`
#### create
* 送信されたパラメータの内容をもとに新しい@userのデータを作成
* strong parameterで、passwordとpassword_confirmationという、has_secure_passwordで提供されたDBにない属性を指定している
* resources :usersを設定したので下記は一緒
`redirect_to user_path(@user)` `redirect_to @user`

### View
`<%= form_for(@user) do |f| %>`
`f.password_field`文字が●●●●●●●●のように伏せられた形

### Model
#### has_secure_password
```
gem 'bcrypt'

class User < ActiveRecord::Base
  has_secure_password
end
```
1. DBにハッシュ化（暗号化）されたpassword_digestを保存する。
2. passwordとpassword_confirmationをモデルに追加して、パスワードの確認が一致するか検証する。
3. パスワードが正しいときに、ユーザーを返すauthenticateメソッドを提供する。

#### validation
* before_saveはコールバックと呼ばれ、データの保存が行われる前にブロックまたはメソッドの処理が実行される
* presence
* length
	* maximum
	* minimum
* format
	* with 正規表現パターン	
* uniqueness
	* case_sensitive 大文字と小文字を区別するか	

### Error
`app/views/users/new.html.erb`
`class: form-control`
バリデーションエラーが出た場合に赤枠表示でエラーが表示
objectには、@userが入る

### Helper
* モデルの情報を受け取って表示用の出力（HTMLタグの表示、テキストの出力）を行うメソッドを入れるモジュール
* モデル・ビュー・コントローラー以外のロジックでも使える
* `image_tag(gravatar_url, alt: user.name, class: "gravatar")`
image_tagメソッドで<img>タグが出力

### flash message
* redirect_toやrenderの前に、flashというハッシュに:success、:alertなどのキーを指定してメッセージを代入
* flashはハッシュなので、eachメソッドでそれぞれのキー（message_type）と値（message）のペアを取り出す

```
<% flash.each do |message_type, message| %>
	<div class="alert alert-<%= message_type %>">
		<%= message %>
	</div> 
<% end %>
```

## Login
### session
* ログイン情報をセッションとして、サーバーとブラウザに保存
* Railsで提供されるsessionという特別な変数にユーザーのidを入れることで、ログイン機能を実現
* ログイン session[:user_id]にユーザーIDを入れる
* ログアウト session[:user_id]をnil

### View
inputのname属性がsession[email]、session[password]

```
<%= form_for(:session, url: login_path) do |f| %>
	<%= f.label :email %>
	<%= f.email_field :email, class: 'form-control' %>
    <%= f.label :password %>
    <%= f.password_field :password, class: 'form-control' %>
    <%= f.submit "Log in", class: "btn btn-primary" %>
<% end %>
```
### Controller
* formで入力したaddressとpasswordはparams[:session]に入っている
### create
* ユーザーをメールアドレスから検索
* ユーザーが見つかった場合、authenticateメソッドでパスワードが正しいか調べる
	* 正しい場合は、session[:user_id]にユーザーIDを入れ、ユーザーの詳細ページにリダイレクト
	* 間違っている場合は’new’テンプレートを表示
### destroy
* session[:user_id]をnil,これでサーバーとブラウザの両方でセッションの情報が破棄されます。
* ルート/にリダイレクトします。

### helper method
`@current_user ||= User.find_by(id:session[:user_id])`

* ||=は左の値がfalseかnilの場合に右の値の代入を行います。変数を初期化する際によく用いられる
* session[:user_id]に一致するユーザーが存在する場合は@current_userにログイン中のユーザー、nilの場合は@current_userにnil
* ||=で代入を行っているのでログインしているユーザーを毎回DBに取りに行かない

`!!current_user`

* current_userが存在する場合、!current_userがfalseになり、もう一度!をつけるとfalseが反転してtrueになります。
* current_userがnilの場合、!current_userがtrueになり、もう一度!をつけるとtrueが反転してfalseになります

`session[:forwarding_url] = request.url if request.get`

* URLを一旦保存しておき、ログイン画面に遷移してログイン後に再び保存したURLにアクセスする場合に使用

## ユーザープロフィール更新
### View
* `edit.html.erb`作成
* form_forほぼnewと一緒

### Controller
1. edit
	* edit画面表示(showと一緒)

1. update
	* DB更新(update_attributesメソッド)
	* render, or redirect
	* logged_in_user　してなかったらログイン画面へ
	* correct_user　違ったらcurrent_userへ

### validation
* ユーザーにログインを要求
* 自分のもののみ更新可能(redirect root)

### others
redirect_to
* HTTPリクエストをサーバーに送り、ユーザーはそこから返ってくるHTMLが表示される
* 1つのActionからは1つのViewしか返せない
* renderやredirect_toを2つ連続して書けない
render

## 投稿機能
### Model
* migration file
外部キー, index追加
複合index追加、今回の場合は投稿を指定ユーザーで絞り込んだ後、作成時間で検索や並び替えを行うという処理がより速く行える

```
  def change
    create_table :microposts do |t|
      t.references :user, index: true, foreign_key: true
      t.text :content

      t.timestamps null: false
      t.index [:user_id, :created_at]  
    end
  end
```
* validation
user_id, content存在する、最大文字数

### UserとMicropost関連付け
#### has_many :microposts
* ユーザーは複数の投稿を持てる
* user.microposts(ユーザーの全投稿)
* user.microposts.new(ユーザーの投稿を作成)
* user.microposts.create(ユーザーの投稿を作成して保存)

#### belongs_to :user
* 投稿は特定のユーザー1人のものである
* micropost.user(投稿したユーザー)

### Controller
* only create
* loginしてるか
* saveできたらrootへ
* できなかったらhomeへ
* `current_user.microposts.build`は、`Micropost.new(user_id: current_user.id)`と同じ
* buildメソッド(has_many :micropostsで生成される)

### View
* render
パーシャル`render 'shared/micropost_form'`
* link_to
すでにあるページ`link_to "Sign up now!", signup_path`

* pluralize
複数形にする
* singularize
単数形にする

### 一覧表示
* desc
新しいものから
* `<%= render @microposts %>`と`<%= render partial: 'microposts/micropost', collection: @microposts %>`は同じ
* 要は、@micropostsからデータを一つ一つ取り出して、micropostというローカル変数として、`app/views/microposts/_micropost.html.erb`に渡している

### Delete
投稿者が現在のユーザーと一致する場合は、リンクにDELETEメソッド

```
    <% if current_user == micropost.user %>
      <%= link_to "delete", micropost, method: :delete,
                                       data: { confirm: "You sure?" } %>
    <% end %>    
```
* `micropost`の部分は`micropost_path(micropost)`と書き換えることができる
* `resources :microposts`と書いたことで、自動的にmicropostからURLが生成されている
* request.referrer
直前に閲覧されていた参照元URL

## Follow機能
### Model
* フォローしている人が増えるごとに、relationshipのデータを作成
* followerとfollowedはどちらもUserクラスのオブジェクト
* `t.index [:follower_id, :followed_id], unique: true`
follower_idとfollowed_idのペアが他のrelationshipとは異なるように

### follower, followed
* `following_relationships`
	* `user.following_relationships`でuserがフォローしている場合のrelationshipの集まりを取得する

```
has_many :following_relationships, class_name:  "Relationship", foreign_key: "follower_id", dependent: :destroy
```


* `following_users`  
	* これに紐付いたユーザー
	* following_relationshipsを経由してフォローしているユーザーの集まりを取得する

```
has_many :following_users, through: :following_relationships, source: :followed
```
* `follower_relationships`
	* `user.follower_relationships`によって、userがフォローされている場合のrelationshipの集まりを取得する

```
  has_many :follower_relationships, class_name:  "Relationship",
                                    foreign_key: "followed_id",
                                    dependent:   :destroy
```
* `follower_users`
	* follower_relationshipsを経由してuserがフォローされているユーザーの集まりを取得する

```
has_many :follower_users, through: :follower_relationships, source: :follower

```


### follow, unfollowメソッド
* follow
	* 現在のユーザーのfollowing_relationshipsの中からフォローするユーザーのuser_idを含むものを探し、存在しない場合は、新しく作成
	* find_or_create_byメソッドは引数のパラメータと一致するものを1件取得し、存在する場合はそのオブジェクトを返し、存在しない場合は引数の内容で新しくオブジェクトを作成し、データベースに保存

* unfollow
	* following_relationshipsからフォローしているユーザーのuser_idが入っているものを探し、存在する場合は削除

* following?
	* 他のユーザーがfollowing_usersに含まれているかチェック

### Controller
* create
	* フォローする他のユーザーのIDをパラメータとして受け取り、見つかったユーザーを引数としてfollowメソッドを実行
* destroy
	* 現在のユーザーのfollowing_relationshipsを検索して他のユーザーをフォローしている場合は、そのユーザーを引数としてunfollowメソッドを実行

### View 
`config.action_view.embed_authenticity_token_in_remote_forms = true`
Ajaxでリクエストを送信する際に、データを安全にやりとりするためにトークンという文字列を付与

createアクションの後に実行されるJavaScript
フォローした後のビューの書き換え

`$("#follow_form").html("<%= escape_javascript(render('users/unfollow')) %>");`

destroyアクションの後に実行されるJavaScript
アンフォローした後のビューの書き換え

`$("#follow_form").html("<%= escape_javascript(render('users/follow')) %>");`

`kill -9 PID`

## 一覧表示
### Controller
* followings


* followers

### View

## タイムライン表示
### Method
### Controller
### View

## Pagenation
## retweet
## お気に入り
## 画像投稿
## 日本語化