CoreDataQueryでデータを保存する [RubyMotion]

# はじめに

前回、"[RubyMotion事始め](http://k-shogo.github.io/article/2014/04/09/rubymotion-get-started/)"では、gem, CocoaPodsを用いて外部ライブラリを利用する方法をまとめました。
今回はCoreDataを利用してデータを永続化する方法をまとめます。

# Core Data Query 利用準備

RubyMotionでCoreDataを扱うために、[cdq (Core Data Query)](https://github.com/infinitered/cdq)を利用します。
まずは`motion`コマンドでプロジェクトを作成し、

```
motion create cdq_sample
cd cdq_sample
```

`Gemfile`に依存関係を記述します。  
画面構成のコードを簡潔にするために、前回同様に
[ProMotion](https://github.com/clearsightstudio/ProMotion)も使用しています。

## Gemfile

```ruby
source 'https://rubygems.org'

gem 'ProMotion'
gem 'cdq'
```

`Gemfile`に依存関係を記述したら、`bundle`コマンドでインストールを行います。

```
bundle install --path vendor/bundle
```

次に`cdq`コマンドでCore Data Queryを使うための準備をしましょう。

```
bundle exec cdq init
```

`init`で作成されるファイルの一つに
`schemas/0001_initial.rb`があります。  
このファイルは`rails`での`migration`ファイルのようなもので、
スキーマを定義します。

```ruby

schema "0001 initial" do

  # Examples:
  #
  # entity "Person" do
  #   string :name, optional: false
  #
  #   has_many :posts
  # end
  #
  # entity "Post" do
  #   string :title, optional: false
  #   string :body
  #
  #   datetime :created_at
  #   datetime :updated_at
  #
  #   has_many :replies, inverse: "Post.parent"
  #   belongs_to :parent, inverse: "Post.replies"
  #
  #   belongs_to :person
  # end

end
```

また、`init`により`Rakefile`にも追記が行われています。  
これは`build:simulator`タスク実行時に`schema:build`も行われることを表しており、
`schema:build`タスクを実行することで`xcdatamodeld `が生成されます。  

```ruby
# -*- coding: utf-8 -*-
$:.unshift("/Library/RubyMotion/lib")
require 'motion/project/template/ios'

begin
  require 'bundler'
  Bundler.require
rescue LoadError
end

Motion::Project::App.setup do |app|
  # Use `rake config' to see complete project settings.
  app.name = 'cdq_sample'
end
task :"build:simulator" => :"schema:build"

```

# Core Data Query でデータを保存してみる

ここから、実際にCore Data Queryを用いてデータを保存してみましょう。  
`schemas/0001_initial.rb`にスキーマを定義します。  
今回は単純に、文字列で`body`をもつ`Item`を作ってみましょう。

```ruby
schema "0001 initial" do

  entity "Item" do
    string :body
  end

end
```

`cdq create model`コマンドでモデルも作成できます。

```
bundle exec cdq create model item
```

#### `app/models/item.rb`

```ruby
class Item < CDQManagedObject

end
```

次に、delegateでCDQをincludeし、on_loadでcdq.setupを呼び出すようにします。

#### `app/app_delegate.rb`

```ruby
class AppDelegate < PM::Delegate
  include CDQ
  def on_load(app, options)
    cdq.setup
    open ItemsScreen.new(nav_bar: true)
  end
end
```

次に、`Item`データを表示する画面を用意します。  

## app/screens/items_screen.rb

```ruby
class ItemsScreen < PM::TableScreen
  title "Items"

  refreshable callback: :on_refresh,
    pull_message: "Pull to refresh",
    refreshing: "Refreshing data..."

  def load_item
    @items = [
      {
        cells: Item.all.map do |item|
          {
            title: item.body,
            action: :tapped_item,
            arguments: item,
          }
        end
      }
    ]
    end_refreshing
    update_table_data
  end

  def on_load
    load_item
  end

  def on_refresh
    load_item
  end

  def table_data
    @items ||= []
  end

  def tapped_item(item)
    p "item #{item.body} tapped"
  end
end
```

準備が出来たので、`rake`コマンドを叩きましょう。
シミュレーターが立ち上がります。
このとき、自動的に`schema:build`タスクも実行され、`xcdatamodeld `が生成されます。
まだデータが登録されていないので、テーブルの内容は空です。

`rake`コマンドで立ち上がったコンソールから、直接データを投入してみます。

```ruby
Item.create body: 'test'
```

シミュレーターに戻り、画面を下に引っ張って更新してみると、テーブルの内容が増えていることが確認できます。

このとき、シミュレーター上でホームボタンを押し、すぐアプリを立ち上げ直しただけでは登録した情報はそのままです。
しかし、コンソールを`exit`で抜けた場合や、ホームボタンをダブルタップしてアプリをバックグラウンドからも削除し、
その後アプリを起動し直すと登録した情報が消えています。
つまりメモリ上にのみ登録されていたわけです。

データを永続化する手順も簡単です。
もう一度`rake`でシミュレータを起動し、再度`Item.create`でデータを登録してみましょう。
今回は永続化するために`cdq.save`コマンドを実行します。

```ruby
Item.create body: 'test2'
cdq.save
```

これでアプリを起動し直してもデータが保存されるようになりました。