Androidはワンツーパンチ 三歩進んで二歩下がる

Android卵プログラマーの記録ブログ

Railsでcsvファイルから初期データを投入する

Railsを勉強中です。

csvファイルから初期データをDBに投入し、画面に表示するという一連の処理をメモします。
railsのバージョンは4.2.6です。

サンプルのアプリケーションを新しく作ります。

$ rails new exm-csv-import

このようなデータを投入します。
f:id:sakura_bird1:20170226212023p:plain


モデルを生成します。

$ rails g model PostalCode local_goverment_code:integer postal_code_old:integer postal_code:integer prefecture_katakana:string ward_katakana:string town_katakana:string prefecture:string ward:string town:string

dbフォルダの下にcsvファイルをコピーします。

db/seeds.rbを次のように編集します。
ここでは、csvファイルにカラム名を記述したヘッダー有りの場合と無しの場合次のようになります。

ヘッダー有りのcsv
f:id:sakura_bird1:20170226213302p:plain

ヘッダー有り

require 'csv'

csv_data = CSV.read('db/postal_code_tokyo_with_header.csv', headers: true)
csv_data.each do |data|
  PostalCode.create!(data.to_hash)
end


ヘッダー無し

require 'csv'

CSV.foreach('db/postal_code_tokyo_seed_no_header.csv') do |row|
  PostalCode.create(:local_goverment_code => row[0],
                    :postal_code_old => row[1],
                    :postal_code => row[2],
                    :prefecture_katakana => row[3],
                    :ward_katakana => row[4],
                    :town_katakana => row[5],
                    :prefecture => row[6],
                    :ward => row[7],
                    :town => row[8])
end

db:migrateをまだ行ってないので実行してから、rake db:seedを実行します。

$ rake db:migrate
$ rake db:seed

これでcsvファイルからテーブルにデータが投入されました。
確認します。

sqliteのコマンドを起動し開発用Databaseに入ります。

sqlite3 db/development.sqlite3
ちなみに
sqlite> .tables
とするとテーブル一覧が表示されます。
postal_codes       schema_migrations


sqlite> .schema postal_codes;
とするとスキーマが表示されます。

CREATE TABLE "postal_codes" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "local_goverment_code" integer, "postal_code_old" integer, "postal_code" integer, "prefecture_katakana" varchar, "ward_katakana" varchar, "town_katakana" varchar, "prefecture" varchar, "ward" varchar, "town" varchar, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL);
sqlite> select * from postal_codes

でテーブルの中身が表示されます。うまくできました。

f:id:sakura_bird1:20170226213806p:plain


このテーブルの一覧を画面に表示します。
コントローラを作成します。

$ rails g controller postal_codes

postal_codes_controller.rb に以下を追加します。

class PostalCodesController < ApplicationController

  # GET /postal_codes
  def index
    @postal_codes = PostalCode.all
  end

end

/app/views/postal_codes/ に index.html.erb を追加し、次のように記述します。

<h1>Listing Postal Codes</h1>

<table>
  <thead>
    <tr>
      <th>LocalGovermentCode</th>
      <th>PostalCodeOld</th>
      <th>PostalCode</th>
      <th>PrefectureKatakana</th>
      <th>WardKatakana</th>
      <th>TownKatakana</th>
      <th>Prefecture</th>
      <th>Ward</th>
      <th>Town</th>
    </tr>
  </thead>

  <tbody>
    <% @postal_codes.each do |postal_code| %>
      <tr>
        <td><%= postal_code.local_goverment_code %></td>
        <td><%= postal_code.postal_code_old %></td>
        <td><%= postal_code.postal_code %></td>
        <td><%= postal_code.prefecture_katakana %></td>
        <td><%= postal_code.ward_katakana %></td>
        <td><%= postal_code.town_katakana %></td>
        <td><%= postal_code.prefecture %></td>
        <td><%= postal_code.ward %></td>
        <td><%= postal_code.town %></td>
      </tr>
    <% end %>
  </tbody>
</table>


/config/routes.rb に以下を追加します。

Rails.application.routes.draw do
  resources :postal_codes
  (略)

rails s でローカルサーバーを起動します。

http://localhost:3000/postal_codes
にアクセスします。

このように表示されます。
f:id:sakura_bird1:20170226214503p:plain

以上です。



Rails Model Generator GUIを使ってrails g modelコマンドを間違わないように書く

rails勉強中です。

railsでモデルとマイグレーションを生成する時のコマンド

rails generate model NAME [field[:type][:index] field[:type][:index]] [options]
(generate はgと略せる。)

こういうものを間違わずに書くいい方法がないかと探したらCodePen - Rails Model Generator GUIなるものを発見しました。
他にも方法があるのかもしれないのですが、私は便利に使うことが出来ました。

codepen.io

表形式で入力してexportボタンを押すとコマンドが生成されるのでコピペしてコマンドラインで実行すればokです。


例)次のようなデータがあり、PostalCodeというmodelを作ります。

f:id:sakura_bird1:20170226135018p:plain

add model ボタンを押して、モデル名を入力。
add attribute ボタンを押して、フィールド名と属性を入力。 n,i,u,a,pはカーソルを上に持っていくと説明が表示されます。

f:id:sakura_bird1:20170226135228p:plain

入力し終わったらexportを押して rails cmdを押すとコマンドが生成されます。

f:id:sakura_bird1:20170226135328p:plain





ちよだニャンとなる会&千代田区共催「ちよだ猫まつり2017」に行ってきました

以前のエントリでご紹介したイベントに行ってきました。

chiyoda-nekofes.jp

sakura-bird1.hatenablog.com


直前まで別の用事があったのですが、幸い千代田区役所に近い場所にいたので終了1時間前に駆け込みました。
千鳥ヶ淵を歩いていたら少しだけ桜が咲いていました。

立派な千代田区役所
f:id:sakura_bird1:20170219155611j:plain

f:id:sakura_bird1:20170219155702j:plain

私が行った時はもう終了間近だったんですが、とても盛況でした。
公式のFacebookでも盛り上がっている様子がわかります。
小池都知事も来てたんですね〜。
愛犬家らしいしちょっと好感度あがっちゃう。

公式Facebookより
https://www.facebook.com/chiyodanekofes/


イベントは、猫グッズなどの販売・展示物・講演・譲渡会・企業のブースなどで成り立っており、収益が飼い主のいない猫の医療費などに使われるようになっています。
写真でどんな雰囲気だったかご紹介します。
猫グッズはかわいいものがたくさんあって見ているだけで楽しかったです。

戦利品
f:id:sakura_bird1:20170219231134j:plain


ネコロジーコーナー
f:id:sakura_bird1:20170219155707j:plain

入り口にでかいコーナーが。アルフィー(懐かしくて涙が出るリアルタイム世代。゚(゚´Д`゚)゚。)の坂崎幸之助さんが保護猫活動がまだまだマイナーだった頃に出版した本の新装版の販売コーナーがありました。
「理想は、世の中から不幸なノラ猫が1匹もいなくなること。猫写真とエッセイで綴る、心温まる保護猫たちとの日々。」
販売をなさっていた方から伺ったのですが、ちよだ猫まつりで販売する分は全額寄付だそうでこれは買うしか無いだろうと。
まだ読んでないんですが、Amazonのレビューを見ると非常に良い内容らしく坂崎さんの素晴らしさが伝わってきましたよ。
ハンカチ用意して読もうと思っています(笑)

↓アフィのリンクですいません。普通の商品ページへのリンクがキレイに出来ず。。。


ちよだニャンとなる会のチャリティくじ。はがきが当たりました。
f:id:sakura_bird1:20170219155746j:plain



日本羊毛アート学園佐藤法雪生徒作品展。すばらしくリアルで「おお~」と自然に声が出ます。
表情がすごい。猫を知っている人達が作ったとわかる。
f:id:sakura_bird1:20170219155833j:plain

f:id:sakura_bird1:20170219155839j:plain

f:id:sakura_bird1:20170219155841j:plain

f:id:sakura_bird1:20170219155852j:plain



イベントの目玉であるリアル猫ヘッド。ホントにリアルなんですよ!
f:id:sakura_bird1:20170219160549j:plain



里親さんの家庭で暮らす猫さんの写真展。みんな良かったねえ。
f:id:sakura_bird1:20170219160627j:plain


猫グッズなどの販売コーナーの一部。店舗数多かったです。
f:id:sakura_bird1:20170219155919j:plain


f:id:sakura_bird1:20170219155941j:plain


f:id:sakura_bird1:20170219155945j:plain


f:id:sakura_bird1:20170219160058j:plain


f:id:sakura_bird1:20170219160109j:plain


f:id:sakura_bird1:20170219160115j:plain


f:id:sakura_bird1:20170219160135j:plain


f:id:sakura_bird1:20170219160151j:plain


f:id:sakura_bird1:20170219160320j:plain


f:id:sakura_bird1:20170219160330j:plain


f:id:sakura_bird1:20170219160411j:plain


f:id:sakura_bird1:20170219160524j:plain


短い間だったけど実際に活動してる人をみると自分も何か!って思って良かったです。
最近はボランティア活動といっても明らかに優れたビジネス的なセンスをお持ちの方々を見るにつけ、外の世界を巻き込んで仕組みを作れるってすごいなあ、猫も助かるなあって感心していたところなのですがこちらでもそう感じました。
色々と自分を振り返って思うことがありますが、それはそれでまた!
主催の方々、参加者の方々、千代田区さん、本当にお疲れ様でした。

AndroidのTextUtilsのisEmptyメソッドとJavaのStringのisEmptyメソッドはわりと違う

年がら年中使っているAndroidのTextUtilsのisEmptyメソッドとJavaのStringのisEmptyメソッドですが、同じ名前で何が違うのか調べたメモです。
TextUtilsクラスのメソッドは全てstaticで定義されていて、JavaのisEmptyメソッドはインスタンス変数から使用する形になっているという違いはありますが、中身はどうでしょう。
それぞれのコードはこのようになっています。

java.lang.String

   public boolean isEmpty() {
        return count == 0;
    }

※countはfinal int の変数で、Stringオブジェクト初期化時にセットされる文字数です。

android.text. TextUtils

   public static boolean isEmpty(@Nullable CharSequence str) {
        if (str == null || str.length() == 0)
            return true;
        else
            return false;
    }

大きな違いは、TextUtilsのisEmptyメソッドはnullチェックがなされている部分です。
メソッドの引数がnullのオブジェクトが渡されてきてもjava.lang.NullPointerExceptionで落ちませんが、JavaのisEmptyメソッドではインスタンス変数がnullの場合は当然落ちます。

例えば次のコードはNullPointerExceptionが発生します。

    public void onFinish(String example) {
        example = null;
        if (example.isEmpty()) {
            Log.d("Example","exampleがemptyです");
        }

以上です。




「ちよだニャンとなる会」さまが「ちよだ猫まつり2017」を開催するそうです+寄付報告

こんにちは。さくらです。
2月って猫の月という感じがしますよね。2/22はにゃんにゃんにゃん!ということで猫の日ですし。

f:id:sakura_bird1:20161208110243j:plain

今日は4ヶ月ぶりぐらいに一般社団法人ちよだニャンとなる会に5000円寄付しました。
f:id:sakura_bird1:20170202195445p:plain


前回のエントリはこれです。
sakura-bird1.hatenablog.com

この頃はポケモンGoにはまっていたんですね。
最近は前ほどやらなくなってしまいました。
レベルは31まで上がっていますが、つい数日前やっとメタモンを捕獲したのがニュースって感じですっかり遅れを取っています。
他にも楽しんだスマホゲームあるけど、1ヶ月以上なかなか続かないですね。世の中のおばちゃんたちはどんなゲームを楽しんでいるのでしょう(・・?



ちよだニャンとなる会と千代田区の主催で「ちよだ猫まつり2017」が開催されるそうです!
同時に猫さんの譲渡会も開催するそうです。
chiyoda-nekofes.jp

千代田区|猫|一般社団法人ちよだニャンとなる会|News & Topics 【2月18日(土曜日)、19日(日曜日)に「ちよだ猫まつり2017」を開催します】

千代田区|猫|一般社団法人ちよだニャンとなる会|News & Topics 【2月19日(日曜日)「ちよだ猫まつり2017」会場にて譲渡会を開催します!】


2月18日と19日の二日間に渡って、東京都千代田区役所で開催されるそうです。
昨年は1万2千人もの来場者があったそうで、大変アツいイベントみたいですよ!
収益は、飼い主のいない猫の医療費などに活用されるそうです。

私は両日とも予定があるのですが、もしかしたら19日行けるかも。
行きたいな。こういった活動に携わっている方々に実際お目にかかりたいという気持ちがあります。
ネコ活もそうなのですが、実際に足を運んでみることで違う世界が広がったり、猫や他の動物を大切に思う気持ちが深まったり、携わっている方々へのリスペクトがガッツリ上がったりするので(●´ϖ`●)

超気軽に出来る二時間以内のボランティア、ねこ活に参加してきました - Androidはワンツーパンチ 三歩進んで二歩下がる


ところでなぜこのイベント情報を知ったかというと、以前寄付してから会報を送ってくださっているからです。
逆に言うとこういうアクションをくださらなかったら知ることはなかったので、情報収集について工夫しないとなと思いました。
あと郵送ってやっぱり強いですね。メールで送られたら見落としそう。

会報をちょっとご紹介します。
新しい家族として迎えられた猫さんのエピソードなどが載っています。

f:id:sakura_bird1:20170202143902j:plain

f:id:sakura_bird1:20170202143942j:plain


以上です。





にゃねっとCLUB 会員登録キャンペーン実施中!

歩きやすくて快適だワン!【ドッグランコーティング】

通院・災害時でもペットを思いやれるリュック【ペットキャリー GRAMP】

【Comelu. for Pet ペット向け乳酸菌サプリ】



緯度・経度から郵便番号を取得する

Geocoderクラスを使って緯度と経度から郵便番号を取得する方法です。
題名は郵便番号を取得するとなっていますが、住所も取得できます。
自分が郵便番号というキーワードで検索していたため自分用メモです。
developer.android.com


Gercoderを使用して住所(郵便番号)を使用する場合はバックエンドサービスを使用するので、インターネットに繋がっていないと取得が出来ません。
Gercoderが使用可能かどうかはisPresent()メソッドで確認します。
コードのサンプルはこんな感じです。

    private String retrievePostalCode(Location location) {
        final Geocoder geocoder = new Geocoder(getApplicationContext());
        if (geocoder.isPresent()) {
            try {
                List<Address> addresses = geocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 1);
                if (addresses != null) {
                    for (Address address : addresses) {
                        if (address.getLocality() != null && address.getPostalCode() != null) {
                            Log.i(TAG,address.getPostalCode());
                            return address.getPostalCode();
                        }
                    }
                } else
                    Log.i(TAG,"No location found..!");
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            Log.i(TAG,"Geocoder is not present");
        }
        return null;
    }





Rails + Grapeを使って超単純なapiを作ってみる

初心者の勉強記録です。
「〜らしい」や「っぽい」などの語尾が多くなっています。
手順を書き残すため、主題とは外れた内容も含みます。
間違ったり知識が最新でなかったりすると思いますのでツッコミ大歓迎でございます。


何をやりたいのか

Androidアプリのサンプル用に単純なAPIを作りたい→Grapeというgemを発見した
現在Railsに興味を持って勉強中なのでRailsを使いたい
サーバーにもデプロイしたい

Grapeの何がいいのか

Rest-LikeなAPIを簡単に作れるDSLらしい
きれいなコードを書けるらしい
使っている人が多そうで情報が豊富そう

Railsとgrapeを組み合わせる利点はあるのか

いい感じの形式を強制されるので、一度導入すれば後で拡張と保守が楽になりそう

サンプルで何を作るのか

固定のjson文字列を返すのみのAPIを作る

GET /api/v1/dummy_api/status
{ code: 1 }

公式サイトを拾い読みメモ

APIバージョンをパスに含める構造を取る
APIに関するコードベースをAPIモジュール配下に設置する
・format は:jsonが推奨されているらしく、xml
# We don't like xml anymore とか言われているが使用不可かどうかまでは調べてない

Controllerの定義は次のような形式になる

# app/controllers/api/v1/hussars.rb
module API
  module V1
    class Hussars < Grape::API
      version 'v1' # path-based versioning by default
      format :json # We don't like xml anymore

      resource :hussars do
        desc "Return list of hussars"
        get do
          Hussar.all # obviously you never want to call #all here
        end
      end
    end
  end
end

このコードだとクライアントから呼び出すパスは/v1/hussars.jsonで終わる

/v1/wings.json で終わるパスであればクラスの定義は↓になる。
API::V1::Wings → app/controllers/api/v1/wings.rb
/v2/hussars.json なら
API::V2::Hussars → app/controllers/api/v2/hussars.rb

APIバージョンについて、すべてのリソースをマウントする集約クラスが必要。

# app/controllers/api/v1/base.rb
module API
  module V1
    class Base < Grape::API
      mount API::V1::Hussars
      mount API::V1::Wings
    end
  end
end

v2だと app/controllers/api/v2/base.rb.

すべてのAPIバージョンを集約するクラスが1つ必要。

# app/controllers/api/base.rb
module API
  class Base < Grape::API
    mount API::V1::Base
    mount API::V2::Base
  end
end

最後に集約クラスをroutes.rbに記述する

# config/routes.rb
Monterail::Application.routes.draw do
  # ...
  mount API::Base => '/api'
  # ...
end

ルーティングはこのようになる

/api/v1/hussars.json -> API::V1::Hussars
/api/v1/wings.json -> API::V1::Wings
/api/v2/hussars.json -> API::V2::Hussars

ファイル構造はこのようになる


その他

簡単なアプリではクラスが多くなりすぎるように思えるが、すぐに元が取れる
rescue_from というのが例外のハンドリングメソッド
Swaggerと結合できる

実装を開始する

Railsアプリを新規で作成

$ rails new hogehoge

Railsにgrapeをインストール

Gemfileに記述する

gem 'grape'

$ bundle install ←記述後に実行しておく

config/application.rbを編集

config.paths.add File.join('app', 'api'), glob: File.join('**', '*.rb')
config.autoload_paths += Dir[Rails.root.join('app', 'api', '*')]

app/api配下にapiを作るので、このフォルダを読み込むためにこの記述が必要

ルーティング

config/routes.rbを編集

mount API => '/'

APIクラスを設置する(リソースを集約したクラスでもある)

class API < Grape::API
  prefix 'api'
  version 'v1', using: :path
  format :json

  helpers do
    def dummy_code
      { code: 1 }
    end

    def err401
      error!('401 Unauthorized', 401)
    end
  end

  resource :dummy_api do

    get :status do
      dummy_code
    end

    get :secret do
      err401
    end
  end
end

rake routesと実行すると次のように表示される。Controllerのルーティングと違う。

$ rake routes
Prefix Verb URI Pattern Controller#Action
   api      /           API

このサイト様によると
・「desc〜」で機能の説明を記述できる
・「get」「post」「put」「delete」と、HTTPのメソッドに対応した処理を定義できる
・「params〜」でパラメータを定義し、「require」で必須かを定義している

プライベートメソッドはhelpers内で行うことになっているらしい

検証

ローカルサーバーを立ち上げる
$ rails s

curlコマンドで確認する
$ curl localhost:3000/api/v1/dummy_api/status
{"code":1}
目論見どおり文字列が返ってくる

サーバーにデプロイする

herokuのアカウントを持っているのでそこにデプロイ

$ heroku login
$ heroku create sakurabird1-grape-example
Creating ⬢ sakurabird1-grape-example... done
https://sakurabird1-grape-example.herokuapp.com/ | https://git.heroku.com/sakurabird1-grape-example.git

$ git push heroku master

このようなエラーメッセージが出るので

remote:        Make sure that `gem install sqlite3 -v '1.3.12'` succeeds before bundling.
remote:  !
remote:  !     Failed to install gems via Bundler.
remote:  !     
remote:  !     Detected sqlite3 gem which is not supported on Heroku.
remote:  !     https://devcenter.heroku.com/articles/sqlite3
remote:  !
remote:  !     Push rejected, failed to compile Ruby app.

deployment - Errors of pushing rails app to Heroku error occurred while installing sqlite3, and Bundler cannot continue - Stack Overflow
を参考にGemfileを直す

group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug'
  gem 'sqlite3'
end

group :production do
  gem 'pg’
end

$ bundle install ←記述後に実行しておく

変更をcommitした後、最新のコードをHerokuにpush

$ git push heroku master

検証

$ curl https://sakurabird1-grape-example.herokuapp.com/api/v1/dummy_api/status
と実行すると
{"code":1}
とレスポンスが返ってくるので成功

このサンプル置き場

github.com