Railsでプラグインを使わずに画像を表示させる

Railsの勉強で作ったサンプルサイトにギャラリーをつけるために、
画像のアップロードと表示の方法を勉強しました。
勉強中なのでプラグインは使わない方法です。
超初心者なので一つ一つ忘れないように勉強したことを残しておきます。

#プロジェクト立ち上げ

##アプリケーション、モデル作成

```
$rails new Gallery
$rails g model Image
```
##テーブル作成
```ruby:db/migrate/20161028_create_image.rb
class CreateImages < ActioveRecord::Migrattion
  def change
    create_table :images do |t|
      t.string :filename
      t.binary :file
      t.timestamps
    end
  end
end
```
画像はバイナリで扱います。

#コントローラ作成
```
rails g controller Images
```

##indexとnewを作成
```ruby:app/controllers/images_controller.rb
class ImagesController < ApplicationController
  def index
    @image = Image
  end

  def new
    @image = Image.new
  end
end
```
とりあえずここまで。
`@image = Image.new`は、新しく作成したImageテーブルのレコードを
`@image`変数に格納して扱えるようにしています。


##createを作成
```ruby:images_controller.rb
~
  def create
    upload_file = image_params[:file]   #image_paramsは後に定義
    image = {} #ローカル変数にからのハッシュを入れて定義
    if upload_file != nil
      image[:filename] = upload_file.original_filename #original_filenameは元々のファイル名を取り出す
      image[:file] = upload.file.read #readでファイル本体を取り出す
    end
  @image = Imag.new(image) #imageを渡して新しくレコードを作る
  if @image.save
    fhash[:success] = "画像を保存しました。"
    redirect_to @image 
  else
    flash[:error] = "保存できませんでした"
    redirect_to "new"
  end
end
```
ここまでで実際のファイルデータの取り出しや格納を行います。
ちなみに、空のハッシュの意味がわからなくて色々調べました。

こちら参考にさせていただきました。
http://ref.xaio.jp/ruby/classes/hash
http://qiita.com/yukimura1227/items/8c972efb27667dfac5cd
私では明確に理解はできなかったのですが、「空で宣言しておいて後から値を入れよう」
ってことなのかな？と理解しています。

##image_paramsを作成
`create`アクションで使った`image_params`を定義。

```ruby:images_controller.rb
~
private
def image_params
  params.require(:image).permit(:filename, :file)
end
```
require:外部のファイルやデータを呼び出す。キーに`image`テーブルを指定。
permit:保存を許可するカラムを指定。
ストロングパラメータ用にどのデータを保存するかを指定しているということだと思います。

##表示用のアクションを作ります。

```ruby:images_controller.rb
def show_image
  @image = Image.find(params[:id])
  send_data @image.file, :type => 'image/jpeg', disposition => 'inline'
end

private
~
```
`send_data`:動的に生成されたデータを出力する。
`:type`:`send_data`のオプション。コンテントタイプを指定。
`:disposition`:`send_data`のオプション。ファイルをインラインで表示するか、ダウンロードして保存するか指定する。


#ルーティング
```ruby:config/routes.rb
Rails.application.routes.draw do
  resources :images        
  resources :images do
    member do　　　　　　　　　　　　　　　　　　　　　　　　
      get "show_image"
    end
  end
end
```
imageテーブルをリソースとしたルーティングを設定します。
`member　do`　　:リソースベースの7つのアクション以外で独自のアクションを呼び出すときに使用。
　　　　        　　　　`member`は特定のデータを対象をしたアクションを呼び出す。
            *`collection do`:全てのデータを対象としたアクションを呼び出す。

これにより`<img src=“/images/:id/show_image”>`で画像にアクセスできるようになり、
`image_tag`で`show_image_image_path(id)`を指定することができるようになります。

#ビュー作成

##index
```ruby:app/views/images/index.html.erb
<% @images.each do |img| %>
  <%= image_tag show_image_image_path(img) %>
<% end %>
```
ルーティングで設定した`show_image`を使って画像にアクセスしています。

##new
```ruby:app/views/images/new.html.erb
<%= form_for(@image) do |f| %>
  <%= f.file_field :file, accept: "image/jpeg" %>
  <%= f.submit "送信する" %>
<% end %>
```
普通に`form_for`を使ってフォームを作ります。
と言っても、`form_for`の使い方についてめっちゃ調べました。

こちら参考にさせていただきました。
http://railsdoc.com/references/form_for
http://qiita.com/shunsuke227ono/items/7accec12eef6d89b0aa9
http://qiita.com/Momozono/items/319bc503e6a5f0963ab9

##show
```ruby:app/views/images/show.html.erb
<%= image_tag show_image_image_path(@image) %>
```
こちらも`show_image`を使ってアクセスしています。


ちなみにRubyのコード見ててよく思うのが、
「同じ単語で違う意味（仕様）のものが多くてわけわからない」なんです。
この場合"image"ですね。テーブル名とか変数名とか工夫すればいいのかな・・・


`image_tag`:イメージタグ<img ~~>を作成
`show_image`:ルーティングで設定したアクション
`_image`:アクセスするテーブル名
`@image`:`show_image`アクションで定義したインスタンス変数

#ハマったこと
##UrlGenerationError in Samples#show
今思えば何のことないのですが、これのお陰で`routes.rb`らへんを色々引っ掻き回してしまいました。
結局URLが間違っていただけでした。

newで送信するまでは良かったのですが、送信後にこのエラーがでます。
原因は送信後のURLが`/images/:id`までしか入力されていなかったからです。
`$rake routes`でルーティングを確認したところ、
`/images/:id/show_image(:format)`となっていたので、
最後に「show_image」をつけなければいけなかったということです。
わざわざそんなことしなくても表示させる方法を今後考えてみます。

ちなみにルーティングの確認についてはこちらで学ばせていただきました。
http://www.rubylife.jp/rails/routing/index1.html


#まとめ
前に書いた通り、やはり私はrailsを勉強するにあたって、「同じ単語で違う意味」のものに
とても弱いことがわかりました。
今回はテーブル名を`image`にしましたが、最初に始めた時は名前を変えて`sample`としていたので、
テーブル名として使われている`image`がどれかわからずとにかくNoMethodやらParameterMissing
やらをやたらくらいました・・・
でもお陰で文法の勉強ができてよかったです！

今回全般的に参考とさせていただいたのはこちらです
http://qiita.com/gaaamii/items/27d27fb7685b39744416
大変お世話になりました。