Ruby on Rails初心者が突破するべきこと一覧

# 環境構築
##やりたいこと
- railsなどのgemはプロジェクトごとにバージョン管理したい。
- githubを基本利用する
- mysqlを利用したい

##前提
- bundleはグローバルにインストールされてる

## 構築
```shell
mkdir project
cd project
bundle init
vim Gemfile
〜〜 gem 'rails'のコメントアウトを外す〜〜
bundle install --path=vendor/bundle
bundle exec rails new . -d mysql
〜〜 Gemfileは上書きしてOK〜〜
git init
vim gitignore
〜〜 https://www.gitignore.io/ を参照〜〜
git remote add origin hogehoge.git
```

`rails new`のオプションに関しては、
`bundle exec rails new -h`で参照してください。
ここではmysqlを指定しますが、デフォルトだとsqlite3になります。

# 知っておくべき基礎
## routes.rb
`root users#index`
=> 初期画面
`resources :posts`
=> シンボリック、複数形

```ruby
resources :posts do
 resources :comments
end
```
=> postの内側にネストされたリソースとしてcommentsが作成される。

## rails generate
`bundle exec rails generate controller Users`
=> 大文字、複数形
`bundle exec rails generate model Post title:string`
=> 大文字、単数形
=> DBは複数形となる。

`bundle exec rails generate model Comment commenter:string body:text article:references`
=> articleモデルと紐づけられる。
=> `belongs_to :article`
=> `article_id`というカラムを生成
=> `article_id`にインデックスを付与

## データ取得
`Post.all`
=> 全てのデータを取得するメソッド。
`Post.first`
=> idがもっとも新しいデータセットを取得するメソッド。
`Post.last`
=> idがもっとも古いデータセットを取得するメソッド

`Post.find`
=> idを検索キーとしてデータを取得する。
=> 該当データがない場合エラーが返る。
`Post.find_by()`
=> idを含む様々な条件で検索するメソッド
=> 複数条件でも検索可能だが、結果は一件のみ。
=> 該当データがない場合nilが返る。
`Post.where()`
=> id以外の条件で検索するメソッド。
=> 該当するデータ全てが返ってくる。

`Post.includes(:user)`
=> N+1問題を解決してPostにUserをjoinしたデータが取得できる。

## link_to
`link_to('リンク名', posts_path)`
`link_to('リンク名', controller: 'posts', action: 'index'`
=> 現在と同じコントローラのアクションにしない場合に利用される。
`link_to('リンク先', '/posts')`
`<%= link_to('Destroy', post_path(post), method: :delete, data: { confirm: 'Are you sure?' }) %>`
=> 削除時にアラート画面を出しながら削除。

## Form
Rails5から`form_tag`や`form_for`に代わって`form_with`が標準化される。
二つが統合したと考えて良くて、かなり構造的に似たものとなった。

```erb
<%= form_with url: post_path, scope: :post do |form| %>
 <%= form.label :title %>
 <%= form.text_field :title %>
 <%= form.submit %>
<% end %>
```
=> `scope`を使うことによって、`params[:scope名][:title]`みたいなアクセスの仕方ができる。
=> 要はパラメータをグループ化してくれる。

```erb
<%= form_with model: Post.new do |form| %>
 <%= form.label :title %>
 <%= form.text_field :title %>
 <%= form.submit %>
<% end %>
```
=> modelを使う場合は、urlとscopeを自動的に推測してくれる。



[参考](https://techracho.bpsinc.jp/hachi8833/2017_05_01/39502)

## Strong parameters
データの受け渡しをパラメータでする際に、何のチェックもしないのは攻撃の絶好の対象となってしまうため対策する。
Railsにはそのセキュリティを高めるための考えとしてStrong Parametersというものがある。
なお、通常同一コントローラー内で複数回パラメータのやり取りはするため、共用できるようにメソッドを切り出し、なおかつ`private`にすることが多い。

```ruby
def create
 @post = Post.new(post_params)
 if @post.save
 end
end

def update
 @post = Post.find(params[:id])
 if @post.update(post_params)
 end
end

private
 def post_params
  params.require(:スコープ名).permit(変数名)
 end
```

## Error
生成するオブジェクト（インスタンス）にエラーがある場合、
そのインスタンスメソッドの`errors`を利用して要因特定ができる。

主に、モデルクラスの`validates`などの定義で問題があった場合に力を発揮する。

```erb
<% if @post.errors.any? %>
 <%= pluralize(@post.errors.count, "error") occured %>
 <ul>
  <% @post.errors.full_messages.each do |error| %>
  <li><%= error %></li>
  <% end %>
 </ul>
<% end %>
```

なお、エラーメッセージを含むフィールドは自動的に`field_with_errors`クラスを持つdivタグで囲まれます。
これを利用して、エラーメッセージをもっと目立たせるようにcssルールを定義できます。

## Partial
### 方法1
アンダースコアつけたファイル名を作成。
`_form.html.erb`などなど。

呼び出しは下記の通り。
`<%= render 'form' %>`

### 方法2
Nestingされている場合、下記のように呼び出すことができる。

`views/comments/_comment.html.erb`のパーシャルを、
`<%= render @post.comments %>`

なお、パーシャルの中では、`comment`という変数で紐づく内容を取得可能。

### 方法3
単純に`views/comments/_form.html.erb`を下記のように呼び出すことも可能。
`<%= render "comments/form" %>`

ビューを出力しているだけなので、パーシャルでもインスタンス変数を利用可能。

## Nesting
ルーティングなどでネストされた関係を構築すると、
書くコード量をかなり減らすことができる。

```ruby:timestamp_migration_file.rb
def change
 create_table :comments do |t|
  t.string :commenter
  t.text :body
  t.references :article, foreign_key: true

  t.timestamps
 end
end
```

```ruby:routes.rb
resources :articles do
 resources :comments
end
```

```ruby:models/article.rb
has_many :comments, dependent: :destroy
```
=> `dependent`を追加することで、記事が削除されたタイミングで関連するコメントも削除することができる。

```ruby:models/comment.rb
belongs_to :article
```

```ruby:controllers/articles_controller.rb
def show 
 @article = Article.find(params[:id])
end
```

```erb:views/articles/show.html.erb
<%= form_with(model: [@article, @article.comments.build]) do |form| %>
...
<% end %>
```

```ruby:controllers/comments_controller.rb
def create
 @article = Article.find(params[:article_id])
 @comment = @article.comments.create(comment_params)
 ...
end

private
 def comment_params
  params.require(:comment).permit(:commenter, :body)
 end
```

[参考](https://qiita.com/jnchito/items/7f41ff3df900909952db)