Alamofireを用いてswiftとRailsと連携してみる

<b>SwiftとRailsの連携する手順をみて試してみたけど、バージョンとか昔の記事だと全然上手くいかない...</b>
なんてことがあるかと思います。そこで参考サイトを元にした更新版の記事を書こうかと思います(初心者向けです)。ほぼ参考サイトと同じなのですが、より詳しく説明していければなと思います！


#参考サイト
参考にしたのは以下の通り。大変分かりやすくてありがとうございます！
[【iOS】SwiftでRailsと連携する方法](https://qiita.com/SoyaTakahashi/items/4a40aefdf13417b1857f)
[【Swift3】Alamofire4系を使ってRailsと連携する](http://hydro-pump.hatenablog.com/entry/2017/09/17/180322)

#環境
OS:macOS Sierra 10.12.6 
Ruby:2.4.2
Rails:5.1.4
iOS:11.1
Xcode:9.1
cocoapods:1.3.1
Alamofire:4.5


#1．準備

##cocoapodsのインストール
ホームディレクトリで以下を実行する

```
$ gem install cocoapods
```
※cocoapodsはgemだけど一度インストールしたらMac自体にインストールされるらしい

インストールされたらxcodeを開いてiOSプロジェクトを作っておく。
SingleViewで場所と名前は適当でOKです。(ここではプロジェクト名をswift_memoとしてます)
プロジェクトのあるディレクトリに移動して以下のコマンドを実行する。

```
$pod setup
$pod init
```

PodfileができればOK!

##Alamofireのインストール
Podfileを開いて、以下のコードをコピ-&ペーストする。(```pod 'Alamofire', '~> 4.5'```と```use_frameworks!```を追記)
なおiOSや[Alamofire](https://github.com/Alamofire/Alamofire)のバージョンは各自変更してください。(Alamofireについては[ここ](https://www.webprofessional.jp/a-crash-course-on-networking-in-ios/))

```:Podfile
# Uncomment the next line to define a global platform for your project
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '11.1'
  use_frameworks!

target 'swift_memo' do
  # Pods for swift_memo
    pod 'Alamofire', '~> 4.5'
  target 'swift_memoTests' do
    inherit! :search_paths
    # Pods for testing
  end

  target 'swift_memoUITests' do
    inherit! :search_paths
    # Pods for testing
  end

end
```

次にXcodeを落として以下を実行。

```
$ pod install
```

<img width="751" alt="スクリーンショット 2017-11-28 23.01.24.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/212058/7eea9c5a-418b-e690-a743-17ba6371bca5.jpeg">

#2．Swift側の設定
##xcodeでプロジェクトを開く
進化したswift_memo.xcworkspace(白色)を開く。
<b>Finder</b>で確認するとプロジェクトが進化してます！

<img width="610" alt="new_project.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/212058/05e831ca-8a67-abc2-5a19-76a502b25263.jpeg">



##部品の配置

Main.storyboradを選択し、適当にヘッダーとタイトルラベル、```保存ボタン```と```Text View```を配置します。Auto Layoutも忘れずにしましょう。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">部品の配置 
<a href="https://t.co/orIVlfEpnn">https://t.co/orIVlfEpnn</a></p>&mdash; Pluto (@Scoripone253) <a href="https://twitter.com/Scoripone253/status/936670464549650432?ref_src=twsrc%5Etfw">2017年12月1日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

※iOS11からSafe Areaが導入され、```Top Layout Guide ```と```Bottom Layout Guide```が消えてるみたいです。詳しくは[ここ](https://qiita.com/eimei4coding/items/5a0794cf7cd13c82b2b5)

##部品とソースコードの関連付け
ViewController.swiftを選択して、Text ViewをtextViewという名前で
<b>Outlet接続</b>、Buttonを<b>tapSaveBtn</b>という名前でAction接続します。

```swift:ViewController.swift
import UIKit

class ViewController: UIViewController {
    
    @IBOutlet weak var textView: UITextView!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    @IBAction func tapSaveBtn(sender: Any) {
        let memo = Memo()
        memo.text = textView.text
        
        StockMemos.postMemo(memo: memo)
    }

}
```

##モデルオブジェクトとモデルマネージャーをつくる
下の画像のように、<b>Models</b>フォルダを作成し、その下に<b>Model Manager</b>フォルダと<b>Model Object</b>フォルダをつくる。
<b>Model Manager</b>フォルダの下には、<b>StockMemos.swift</b>というNSObjectのファイルをつくり、<b>Model Object</b>フォルダの下には、<b>Memo.swift</b>というNSObjectのファイルをつくる。


<img width="267" alt="model2.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/212058/9e07b024-47e9-b7da-6314-3f211f074649.jpeg">


##コードの記述
メモクラスにtextプロパティを持たせる。

```swift:Memo.swift
import UIKit

class Memo: NSObject {
    var text: String = ""
}
```

HTTP通信に必要な処理を書いていく。

```swift:StockMemos.swift
import UIKit
import Alamofire

class StockMemos: NSObject {
    
    // 保存ボタンが押されたときに呼ばれるメソッドを定義
    class func postMemo(memo: Memo) {
        
        let params: [String: AnyObject] = [
            "text": memo.text as AnyObject
        ]
        
        // HTTP通信
        // Both calls are equivalent
        Alamofire.request("http://localhost:3000/api/memos", method: .post, parameters: params)
        
    }
}
```

上記の2つのswiftファイルはコピペでOK。
最後に```info.plist```に以下を追加してhttp通信から推奨しているhttps通信に変更する。
App Transport Security Settings（型：Dictionary）を追加。その中にAllow Arbitrary Loadsを入れる。ValueをYesにすることを忘れずに。



#3．Rails側の設定
ここではRuby及びRailsの導入については省略します。
(ブラウザーで[http://localhost:3000/](http://localhost:3000/)を開き、コマンド```rails s -b 0.0.0.0```でサーバーを立ち上げ、<b>Yay! You’re on Rails!</b>が表示されてればおkです)

##Railsアプリをつくる

```
$ rails new Meomoo -d mysql
```

場所は適当でOKです。

##DBをつくる

```
$ bundle exec rake db:create
```
##ルーティングの設定
Meommo/config/routes.rbを開き、以下のコードを記述する。apiのディレクトリをはさんでコントローラーをつくるため、namespaceでルーティングを設定。

```ruby:routes.rb
Rails.application.routes.draw do

  namespace :api, default: {format: :json} do
    resources :memos, only: :create
  end

end
```


##モデルの作成

```
$ rails g model memo
```

##カラムの追加
Meommo/db/migrate/○○○○○○_create_memos.rbを開き、```t.text :text```を以下のファイルに
追記する。

```○○○○○○_create_memos.rb
class CreateMemos < ActiveRecord::Migration [5.1]
  def change
    create_table :memos do |t|
      t.text :text
      t.timestamps
    end
  end
end
```

DBに反映させる。

```
$ bundle exec rake db:migrate
```

##コントローラーの作成とcreateアクション
apiディレクトリ配下にmemos_controller.rbを作成

```
$ rails g controller api/memos
```

次にMeommo/app/controllers/api/memos_controller.rbを開き、以下のように記述する。

```ruby:memos_controller.rb
class Api::MemosController < ApplicationController
  skip_before_action :verify_authenticity_token, only: :create # どうやらこの記述が必要

  def create
    memo = Memo.new(create_params)

    # エラー処理
    unless memo.save # もし、memoが保存できなかったら
      @error_message = [memo.errors.full_messages].compact # エラーが入ってるインスタンス変数を定義
    end
  end


  private
  def create_params
    params.permit(:text)
  end
end
```

※2行目の```skip_before_filter```だとなんかエラー吐いてくるので```skip_before_action```にしてます。

##createアクションに対応するビュー(JsonJbuilder)をつくる
以下のディレクトリにcreate.json.jbuilderファイルをつくる。

```
$ vi Meommo/app/views/api/memos/aaa.json.jbuilder
```

```create.json.jbuilder
json.error_message @error_message if @error_message
```

##バリデーションの設定
textが空のまま送信してきたらエラ-メッセージを返す。

```
Meommo/app/models/memo.rb
```

```ruby:memo.rb
class Memo < ApplicationRecord
  validates :text, presence: true
end
```

#4．テストしてみる
ターミナルから```rails s -b 0.0.0.0```でサーバー立ち上げて、```http://localhost:3000/```
でサーバーが立ち上がってるか確認。
確認できたら、実際に実行してみる(以下の動画参照)

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">メモ帳とDB連携<a href="https://t.co/lMfRhF7xkr">https://t.co/lMfRhF7xkr</a></p>&mdash; Pluto (@Scoripone253) <a href="https://twitter.com/Scoripone253/status/939050262701805568?ref_src=twsrc%5Etfw">2017年12月8日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

ここまでできればメモ帳で入力した文字がDB(MySQL)に保存されるはずです。お疲れ様でした。

#5．終わりに
ここまで色々と書きましたが、間違ってるところがあれば是非コメントよろしくお願い致します。
つまづくところとしてはxcodeのエラーのとこだと思うので、頑張ってGoogleで調べてみるか詳しい方に聞くのが一番大事かと思います。