Railsメモ - 初心者を抜け出す助けになるかもまとめ


完全に自分用にまとめたのですが、初心者には盲点になりそうなところが多くもしかしたら役立つかもしれないな、ということで公開。修正・アドバイス等あればコメントください。

主には、『たのしいRuby』と『Ruby on Rails4 アプリケーションプログラミング』のまとめです。
# たのしいRuby
## require
requireは使いたいライブラリのファイルを読み込む。
例："uri"
メモ：以下のモジュールのincludeなどがクラスに対するものだとしたら、ファイルに対するincludeみたいなものかな？

## モジュール
### クラスとの違い
モジュールはメソッドを提供し、クラスに似ているが以下の点で違う

* インスタンスを作成できない
* 継承できない

### includeとextend

基本的にはRailsのヘルペーみたいにどこでも（？）呼び出せる

```ruby
module Test
	def explain(name)
		p "#{name}さん、これはテストです"
	end
end

Test::explain("田中") #=> "田中さん、これはテストです"

```

includeすると、インスタンスメソッドに追加される

```ruby
module Test
	def explain(name)
		p "#{name}さん、これはテストです"
	end
end

class MyClass
include Test

end

test = MyClass.new
test.explain("田中") #=> "田中さん、これはテストです"

```

extendすると、クラスメソッドに追加される

```ruby

module Test
	def explain(name)
		p "#{name}さん、これはテストです"
	end
end

class MyClass
extend Test

end

MyClass.explain("田中") #=> "田中さん、これはテストです"

```

## 例外処理
### 基本系

```ruby
begin
	# 通常の処理
	raise "メッセージ" # RuntimeErrorが発生
	raise 例外クラス # 指定した例外の発生
	raise 例外クラス, "メッセージ" #指定した例外を発生させ、そのオブジェクトにメッセージをセット
	raise # RuntimeError
rescue
	# error処理
	# $で例外オブジェクトにアクセスできる
	# $! => 最後に発生した例外 $@ => 最後に発生した例外の位置に関する情報
	raise # $!をもう一度発生させる
ensure
	# 例外の有無にかかわらず実行される処理
end
```

### 例外オブジェクト
#### 呼び出せるメソッド

* class : 例外の種類
* message : 例外のメッセージ
* backtrace : 例外が発生した位置に関する情報

## ブロック
```ruby
def total(from, to)
	result = 0
	from.upto(to) do |num|
		if block_given?          # ブロックが渡されていたら
			result += yield(num) # numを引数として渡されたブロックを実行
		else
			result += num
		end	
	end
	return result
end

p total(1, 10)                    # 1から10の和 => 55
p total(1, 10) { |num| num ** 2 } # 1から10の2乗の値の和 => 385

```

ブロックの中で`break`を呼びと、nilになる。`break 0`など値を渡すと戻り値が設定される

**あとは辞書的に使おう笑**

# Rails アプリケーションプログラミング の学びまとめ
## View
### debugを使おう
`debug(@items)`といった形で、変数の中身をviewに表示できる。

### 簡単な部分テンプレートのcapture

```slim
- @current = capture do
	= "ただいまの時刻は#{Time.now}です。"

= @current
div.container = @current
```

## Model
### Validation
こうやると綺麗にかけるのか

```ruby
class Book < ActiveRecord::Base
	validates :isbn,
		presence:   true,
		uniqueness: true,
		length:     { is: 17 },
		format:     { with: /¥a[0-9]/ }
	validates :title
		# ...(省略
```
#### データベースに関連づかないモデルを定義する
フォームからの入力を検証したい時など

```ruby
# app/models/search_keyword.rb
class SearchKeyword
	include ActiveModel::Model
	
	attr_accessor :keyword
	
	validates :keyword, presene: true
end

# record_controller

def keywd
	@search = SearchKeyword.new
end

def keywd_process
	@search = SearchKeyword.new(params[:search_keyword])
	if @search.valid? # ここでバリデーターを呼び出す。
		render text: @search.keyword
	end
end

		

```


## Controller
### 基本認証：簡易なログイン実装
ひとまず管理者のみにしたいときとか。

```ruby
class CtrlController < ApplicationController

	before_action :auth, only: :index
	
	private
		
	def auth
		# 認証に使う名前とパスワード
		name = 'kimuko'	
		passwd = '8dohardk4kfn45ngiij4359058'
		
		#基本認証を実行
		authentiate_or_request_with_http_basic('Railsbook') do |n, p|
			n == name && Digest::SHA1.hexdigest(p) == passwd
		end
	end
end	
```

### 例外処理

```ruby:application_controller.rb
class ApplicationController < ActionController::Base
	protect_from_forgery with: :exception
	
	rescue_from ActiveRecord::RecordNotFound, with: :id_invalid
	
	private
	
	def id_invalid(e)
		# 404用のビュー
		render 'shared/record_not_found', status: 404
	end

```
デフォルトでは`public/404.html`や`public/500.html`に飛ばされる。

### 独自のフラッシュメッセージの追加
以下のように追加できる。

```ruby
class ApplicationController < ActionController::Base
	add_flash_types :info
end
```

### 複数コントローラー共通の処理
`app/controllers/concerns`にまとめる

```ruby:sample.rb
module Name
	extend ActiveSupport::Concern
	
	included do
		# call_clazz
		before_filter :check_logined
	end
	
	module ClassMethods
		#定義
	end
	
	#インスタンスメソッドの定義
	
	private
	
	def check_logined
	end
end
```

そして、読み込みたい側で`include Name`とすればOK

## ルーティング
### namespaceとscopeの違い
`namespace`：参照コントローラー、URLパターン、Urlヘルパーも変わる（RESTful）
`scope module`：参照コントローラーは変わるが、その他は変わらない
※`scope`はコントローラーは変えないが、URLだけ変える

### path_name
newやeditなどの標準アクションに関連づいたURLを変更したいならば、:path_namesオプションを指定。これやりたかった...!

```ruby
resources :reviews, path_names: { new: :insert, edit: :revise }
```

### ネストを浅くするshallowオプション
```ruby
resources :books do
	resources :reviews, shallow: true
end
```
こうすると、`reviews`リソースがidを受け取らない、index,new,createアクションでのみ`:book_id`が入り、それ以外は、`id`のみのパスが出来上がる。

さらにscopeとshallow_pathを利用すると、reviewsリソース時に、`books/`ではなく`b/`を指定できたりする。

```ruby
scope shallow_path: :b do
	resources :books do
		resources :reviews, shallow: true
	end
end
```

## キャッシュについて
サイトのスケーラビリティを考えたら必須の機能。これ以外にもありそうだけど本書ではフラグメントキャッシュを利用。
### 基本
```slim
- cache do
	= Time.new
	br
```
ビューヘルパーcacheでキャッシュしたい領域を囲うだけ。簡単！！

### 同一ページでのキャッシュキー
基本的にキャッシュキーで管理しているらしいが、複数のキャッシュが同一ページにあるとキーが重複してしまう、とのこと。なので以下のように指定

```slim
- cache(suffix: 'footer') do
	= Time.new
	br

```


### キャッシュキーの複数ページでの共有
同一のキャッシュキーを利用すればOK

### キャッシュキーの決め方
#### モデルを元に
```slim
- cache(book) do
	#ビュー
```
このようにモデルのオブジェクトを渡すと`モデル名.id値-updated_at列の値`というキーを生成してくれるらしい。これなら更新しててもわかるね。

##### 親子関係にあるモデルにおける注意点
```ruby:review.rb
class Review < ActiveRecord::Base
	belongs_to :book, touch: true
end
```
この`touch: true`があれば、親のupdated_atも更新されるので最新のキャッシュを保てるとのこと。

##### 一覧画面とかは？
```slim
- cache(books_cache_key) do

```

```ruby
module ExtraHelper
	def books_cache_key
		"books-#{Book.count}-#{Book.maximum(:updated_at).to_i}"
	end
end
```
ヘルパーを拡張して作っちゃおう。

##### 条件つき
```slim
- cache_if(book.published <= Date.today, book)
```
的な。

※注意：キャッシュはメモリの上限まで累積する。最終アクセス日などから判断して定期的に削除すること