{"action":"created","comment":{"url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/pulls/comments/39000532","id":39000532,"diff_hunk":"@@ -0,0 +1,254 @@\n+---\n+title: Rails で動的にテーブルを作成して、大きな CSV のデータをインポートする方法\n+date: 2015-09-08 20:52 JST\n+authors: e-takano\n+tags: rails\n+---\n+\n+こんにちは！ SQL 大好き kano-e です。\n+\n+「データ更新のたびに新規にテーブルを作って、そこにデータを投入したい」とか。\n+「お客様毎にテーブルを分けたいが、お客様情報は DB に保存されていて、増減するので migration で作っておくことができない」とか。\n+以外と遭遇率が高い状況です。\n+\n+この記事では、そんな時に多分役立つ「Railsで動的にテーブルを作成して、大きな CSV のデータをインポートする方法」について、思いつくままにまとめてみました。\n+合わせて読みたい「動的に作成したテーブルを db/schema.rb に含めない方法」のおまけ付きです。\n+\n+\n+<!--more-->\n+\n+## はじめに\n+\n+この記事では、以下の内容について書いています。\n+\n+* Rails で動的にテーブルを CREATE/DROP する\n+* テーブルに対応するモデルを用意せずに SQL を組み立て/発行する\n+* サイズの大きい CSV のデータを DB (PostgreSQL) に投入する\n+\n+動作確認環境は、以下になります。\n+\n+* Ruby 2.2.3\n+* Rails 4.2.4\n+* PostgreSQL 9.4.0\n+\n+## 動的にテーブルを作成したり削除したりしたい\n+\n+### テーブルの作成: create_table\n+\n+Rails だと、動的にテーブルを作るのは簡単で\n+\n+```\n+ActiveRecord::Base.connection.create_table(table_name) do |t|\n+  t.string :code   t.string :name\n+end\n+```\n+\n+のように書けば、テーブルを作れてしまいます。\n+\n+見ての通り、この書き方はいつもの migration と同じです。\n+\n+例えば\n+\n+* Product というモデルがあって\n+* name というユニークな attributes を持っている時に\n+* Product インスタンス毎にテーブルを作成したい\n+\n+という場合、以下のように書きます。\n+\n+```\n+class Product < ActiveRecord::Base\n+  def create_temporary_table\n+    ActiveRecord::Base.connection.create_table(\"temporary_#{name}\") do |t|\n+      t.string :title\n+      t.string :description\n+    end\n+  end\n+end\n+```\n+\n+これで `Production#create_temporary_table` を呼ぶと `CREATE TABLE` が発行されて、新しいテーブルが作成されます。\n+\n+### テーブルの存在確認: table_exists?\n+\n+作成済みかどうかを判断したい場合は `#table_exists?` が使えます。\n+\n+```\n+ActiveRecord::Base.cnnection.table_exists?(table_name)\n+```\n+\n+テーブルが存在しなかった場合のみ新規作成する、といったことができるようになりました。\n+\n+### テーブルの削除: drop_table\n+\n+テーブルの削除は、もうお分かりかと思いますが `#drop_table` が使えます。\n+\n+```\n+ActiveRecord::Base.connection.drop_table(table_name)\n+```\n+\n+ここまでで「古いテーブルが存在した場合は削除してから、新しいテーブルを作成する」にも対応可能です。\n+\n+## 動的に作成したテーブルの操作\n+\n+### 対応するモデルを作成する\n+\n+動的に作成したテーブルを操作するために一番簡単な方法は、対応するモデルを作ることかと思います。\n+\n+その場合、テーブルが動的なのでモデルも動的に生成する必要があります。\n+\n+```\n+klass = Class.new(ActiveRecord::Base) do |c|\n+  c.table_name = table_name\n+end\n+Object.const_set(model_name, klass)\n+```\n+\n+何度も `Class.new` するのは効率が悪いので、あらかじめ `Object.const_get(model_name)` で確認し、何度も同じクラスを作らないようにした方が良いです。\n+でないと、無駄に Class インスタンスが生成され続けてしまいます。\n+\n+動的にカラムが変わる可能性がある場合には、Class インスタンスを使いまわしているとスキーマに追随できなくなってしまうため、テーブルを作り直すなどのタイミングで `klass.reset_column_information` を呼ぶ必要があります。\n+\n+### モデルを作らずに SQL を実行する\n+\n+モデルを作らずに `ActiveRecord::Base.connection.execute` で頑張ることも可能です。\n+\n+SQL 組み立て時に、埋め込む値を適宜クオートするために `#quote_table_name` と `#quote_column_name` が使えます。\n+(クオートしなくても動くことは多いですが、クオートする方が安心ですよね)\n+\n+```\n+ActiveRecord::Base.connection.quote_table_name('table_name')\n+ActiveRecord::Base.connection.quote_column_name('column_name')\n+```\n+\n+これで、それぞれテーブル名とカラム名が、使っている RDB に応じてクオートされます。\n+\n+カラムに入れる値のクオートは、カラムの型情報などが必要になるため、一手間だけ余分に必要です。\n+\n+モデルが存在する場合は `ModelClass.column_for_attribute(column_name)` で取得できるのですが、なにせ今回はモデルを作っていません。\n+\n+モデルを作りたくなる気持ちを無視して、まずはカラムの情報を取得します。\n+\n+```\n+ActiveRecord::Base.connection.columns(table_name)\n+```\n+\n+これでカラム情報が Array で返ってきます。\n+Array の中から値を投入するカラムを見付け、それをクオートしたい値とともに `#quote` に渡します。\n+\n+```\n+columns = ActiveRecord::Base.connection.columns(table_name)\n+column = columns.find{|c| c.name == column_name }\n+ActiveRecord::Base.connection.quote(value, column)\n+```\n+\n+それらを利用して SQL を組み立て `ActiveRecord::Base.connection.execute` に渡せば SQL の結果が返ってきます。\n+\n+```\n+connection = ActiveRecord::Base.connection\n+\n+count_sql = \"SELECT COUNT(*) AS #{connection.quote_column_name('count')} FROM #{connection.quote_table_name(table_name)}\"\n+count_result = connection.execute(count_sql)\n+count_result.first #=> {\"count\" => 0}\n+\n+column = connection.columns(table_name).find{|c| c.name == column_name }\n+update_sql = <<\"SQL\"\n+UPDATE #{connection.quote_table_name(table_name)}\n+  SET #{connectionn.quote_column_name(column_name)} = #{connection.quote(str, column)}\n+  WHERE #{connectionn.quote_column_name(column_name)} IS NULL\n+SQL\n+update_result = connection.execute(update_sql)\n+update_result.cmd_status #=> \"UPDATE 2\"\n+update_result.cmd_tuples #=> 2\n+```\n+\n+## 行数の多い CSV のデータを DB に投入したい\n+\n+PostgreSQL には CSV のデータをテーブルに投入するための方法が、いくつか用意されています。\n+\n+例えば、PostgreSQL が動いているサーバ上に CSV が配置できるのであれば COPY にファイルパスを渡すことで、データ投入が可能です。\n+残念ながら、この方法は RDS の場合にはできません。\n+\n+メタコマンドの `\\copy` であればリモートの CSV も渡せるのですが、その場合 pg gem ではメタコマンドを使用できませんので、 pg を経由せずに直接 psql を操作しないといけません。\n+\n+`COPY` に標準入力を渡す SQL を書くことも可能です。\n+例えば対象の CSV を元に以下のような SQL ファイルを作って\n+\n+```\n+COPY table_name (column1, column2, column3) FROM stdin WITH csv;\n+data1,data2,data3\n+...\n+\\.\n+```\n+\n+これを psql に渡します。\n+\n+```\n+$ psql -U username -h host --dbname database --file=/path/to/copy.sql\n+```\n+\n+ただし、この場合も `\\copy` と同じく、直接 psql コマンドを操作する必要があります。\n+\n+Rails プロセスから、手軽に COPY を使いたい場合は [postgres-copy](https://github.com/diogob/postgres-copy) という gem を使うのが良さそうです。\n+\n+pg gem にはもともと COPY を実行するメソッドがあり、 postgres-copy はそれを柔軟に扱えるようにラッピングしてくれています。\n+\n+```\n+ModelName.copy_from '/path/to/copy.csv', tabel: table_name, columns: [column1, column2, column3]\n+```\n+\n+詳細な使い方はこの記事では省きますが、モデルのテーブルにデータ投入するだけであれば、`copy_from` にCSVのパスだけ渡せば使えます。\n+今回のケースでは動的にテーブルが作成されているため table や columns などのオプションを渡しています。\n+\n+postgres-copy を使う利点としては、\n+\n+* CSV 以外にも、複数のフォーマットのデータを扱える\n+* テーブルスキーマと CSV データのマッピングを手軽に行える\n+* CSV の内容に手を加えた上で投入できるようになっている\n+\n+辺りでしょうか。\n+\n+ただし postgres-copy が CSV の毎行処理を行っている分、(多少ではありますが) CPU 負荷もかかります。\n+\n+* ファイルのフォーマットがある程度決まっていて\n+* 手を加える必要なくデータ投入できる\n+\n+ようなケースでは、直接 pg の copy_data を使っても手間はさほど変わりません。","path":"source/posts/2015-09-08-modelless-table-on-rails.html.md","position":215,"original_position":215,"commit_id":"d5706619ebd93fc049d36b252e8124a30939dc8b","original_commit_id":"d5706619ebd93fc049d36b252e8124a30939dc8b","user":{"login":"a-know","id":1097533,"avatar_url":"https://avatars.githubusercontent.com/u/1097533?v=3","gravatar_id":"","url":"https://api.github.com/users/a-know","html_url":"https://github.com/a-know","followers_url":"https://api.github.com/users/a-know/followers","following_url":"https://api.github.com/users/a-know/following{/other_user}","gists_url":"https://api.github.com/users/a-know/gists{/gist_id}","starred_url":"https://api.github.com/users/a-know/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/a-know/subscriptions","organizations_url":"https://api.github.com/users/a-know/orgs","repos_url":"https://api.github.com/users/a-know/repos","events_url":"https://api.github.com/users/a-know/events{/privacy}","received_events_url":"https://api.github.com/users/a-know/received_events","type":"User","site_admin":false},"body":"上で `pg gem ではメタコマンドを使用できませんので、 pg を経由せずに直接 psql を操作しないといけません` とあるけど、最終的に `pg の copy_data` に行き着いた、というあたりが、内部的にどんなことをやっているかを含め、もう少し書いてあると嬉しいかなと思いました！ :smiley: ","created_at":"2015-09-09T01:51:59Z","updated_at":"2015-09-09T01:51:59Z","html_url":"https://github.com/feedforce/tech.feedforce.jp/pull/121#discussion_r39000532","pull_request_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/pulls/121","_links":{"self":{"href":"https://api.github.com/repos/feedforce/tech.feedforce.jp/pulls/comments/39000532"},"html":{"href":"https://github.com/feedforce/tech.feedforce.jp/pull/121#discussion_r39000532"},"pull_request":{"href":"https://api.github.com/repos/feedforce/tech.feedforce.jp/pulls/121"}}},"pull_request":{"url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/pulls/121","id":44430406,"html_url":"https://github.com/feedforce/tech.feedforce.jp/pull/121","diff_url":"https://github.com/feedforce/tech.feedforce.jp/pull/121.diff","patch_url":"https://github.com/feedforce/tech.feedforce.jp/pull/121.patch","issue_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/issues/121","number":121,"state":"open","locked":false,"title":"[WIP] Add article modelless-table-on-rails","user":{"login":"kano-e","id":2674819,"avatar_url":"https://avatars.githubusercontent.com/u/2674819?v=3","gravatar_id":"","url":"https://api.github.com/users/kano-e","html_url":"https://github.com/kano-e","followers_url":"https://api.github.com/users/kano-e/followers","following_url":"https://api.github.com/users/kano-e/following{/other_user}","gists_url":"https://api.github.com/users/kano-e/gists{/gist_id}","starred_url":"https://api.github.com/users/kano-e/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kano-e/subscriptions","organizations_url":"https://api.github.com/users/kano-e/orgs","repos_url":"https://api.github.com/users/kano-e/repos","events_url":"https://api.github.com/users/kano-e/events{/privacy}","received_events_url":"https://api.github.com/users/kano-e/received_events","type":"User","site_admin":false},"body":"まだ見直し中なので WIP だけど、指摘などは随時受付中です。","created_at":"2015-09-08T13:14:50Z","updated_at":"2015-09-09T01:51:59Z","closed_at":null,"merged_at":null,"merge_commit_sha":"b7ea7cb0499b0cba973048bd7915a7391cb51c6c","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/pulls/121/commits","review_comments_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/pulls/121/comments","review_comment_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/pulls/comments{/number}","comments_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/issues/121/comments","statuses_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/statuses/d5706619ebd93fc049d36b252e8124a30939dc8b","head":{"label":"feedforce:article-modelless-table","ref":"article-modelless-table","sha":"d5706619ebd93fc049d36b252e8124a30939dc8b","user":{"login":"feedforce","id":4169389,"avatar_url":"https://avatars.githubusercontent.com/u/4169389?v=3","gravatar_id":"","url":"https://api.github.com/users/feedforce","html_url":"https://github.com/feedforce","followers_url":"https://api.github.com/users/feedforce/followers","following_url":"https://api.github.com/users/feedforce/following{/other_user}","gists_url":"https://api.github.com/users/feedforce/gists{/gist_id}","starred_url":"https://api.github.com/users/feedforce/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/feedforce/subscriptions","organizations_url":"https://api.github.com/users/feedforce/orgs","repos_url":"https://api.github.com/users/feedforce/repos","events_url":"https://api.github.com/users/feedforce/events{/privacy}","received_events_url":"https://api.github.com/users/feedforce/received_events","type":"Organization","site_admin":false},"repo":{"id":27247535,"name":"tech.feedforce.jp","full_name":"feedforce/tech.feedforce.jp","owner":{"login":"feedforce","id":4169389,"avatar_url":"https://avatars.githubusercontent.com/u/4169389?v=3","gravatar_id":"","url":"https://api.github.com/users/feedforce","html_url":"https://github.com/feedforce","followers_url":"https://api.github.com/users/feedforce/followers","following_url":"https://api.github.com/users/feedforce/following{/other_user}","gists_url":"https://api.github.com/users/feedforce/gists{/gist_id}","starred_url":"https://api.github.com/users/feedforce/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/feedforce/subscriptions","organizations_url":"https://api.github.com/users/feedforce/orgs","repos_url":"https://api.github.com/users/feedforce/repos","events_url":"https://api.github.com/users/feedforce/events{/privacy}","received_events_url":"https://api.github.com/users/feedforce/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/feedforce/tech.feedforce.jp","description":"feedforce Engineers' blog","fork":false,"url":"https://api.github.com/repos/feedforce/tech.feedforce.jp","forks_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/forks","keys_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/keys{/key_id}","collaborators_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/teams","hooks_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/hooks","issue_events_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/issues/events{/number}","events_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/events","assignees_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/assignees{/user}","branches_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/branches{/branch}","tags_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/tags","blobs_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/git/refs{/sha}","trees_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/git/trees{/sha}","statuses_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/statuses/{sha}","languages_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/languages","stargazers_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/stargazers","contributors_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/contributors","subscribers_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/subscribers","subscription_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/subscription","commits_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/commits{/sha}","git_commits_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/git/commits{/sha}","comments_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/comments{/number}","issue_comment_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/issues/comments{/number}","contents_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/contents/{+path}","compare_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/compare/{base}...{head}","merges_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/merges","archive_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/downloads","issues_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/issues{/number}","pulls_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/pulls{/number}","milestones_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/milestones{/number}","notifications_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/labels{/name}","releases_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/releases{/id}","created_at":"2014-11-28T01:42:34Z","updated_at":"2015-05-07T02:33:06Z","pushed_at":"2015-09-09T01:51:23Z","git_url":"git://github.com/feedforce/tech.feedforce.jp.git","ssh_url":"git@github.com:feedforce/tech.feedforce.jp.git","clone_url":"https://github.com/feedforce/tech.feedforce.jp.git","svn_url":"https://github.com/feedforce/tech.feedforce.jp","homepage":"http://tech.feedforce.jp/","size":16475,"stargazers_count":3,"watchers_count":3,"language":"CSS","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":4,"mirror_url":null,"open_issues_count":4,"forks":4,"open_issues":4,"watchers":3,"default_branch":"master"}},"base":{"label":"feedforce:master","ref":"master","sha":"a15ef24d60ffafd2716de24517a10ed10fc05fb1","user":{"login":"feedforce","id":4169389,"avatar_url":"https://avatars.githubusercontent.com/u/4169389?v=3","gravatar_id":"","url":"https://api.github.com/users/feedforce","html_url":"https://github.com/feedforce","followers_url":"https://api.github.com/users/feedforce/followers","following_url":"https://api.github.com/users/feedforce/following{/other_user}","gists_url":"https://api.github.com/users/feedforce/gists{/gist_id}","starred_url":"https://api.github.com/users/feedforce/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/feedforce/subscriptions","organizations_url":"https://api.github.com/users/feedforce/orgs","repos_url":"https://api.github.com/users/feedforce/repos","events_url":"https://api.github.com/users/feedforce/events{/privacy}","received_events_url":"https://api.github.com/users/feedforce/received_events","type":"Organization","site_admin":false},"repo":{"id":27247535,"name":"tech.feedforce.jp","full_name":"feedforce/tech.feedforce.jp","owner":{"login":"feedforce","id":4169389,"avatar_url":"https://avatars.githubusercontent.com/u/4169389?v=3","gravatar_id":"","url":"https://api.github.com/users/feedforce","html_url":"https://github.com/feedforce","followers_url":"https://api.github.com/users/feedforce/followers","following_url":"https://api.github.com/users/feedforce/following{/other_user}","gists_url":"https://api.github.com/users/feedforce/gists{/gist_id}","starred_url":"https://api.github.com/users/feedforce/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/feedforce/subscriptions","organizations_url":"https://api.github.com/users/feedforce/orgs","repos_url":"https://api.github.com/users/feedforce/repos","events_url":"https://api.github.com/users/feedforce/events{/privacy}","received_events_url":"https://api.github.com/users/feedforce/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/feedforce/tech.feedforce.jp","description":"feedforce Engineers' blog","fork":false,"url":"https://api.github.com/repos/feedforce/tech.feedforce.jp","forks_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/forks","keys_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/keys{/key_id}","collaborators_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/teams","hooks_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/hooks","issue_events_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/issues/events{/number}","events_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/events","assignees_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/assignees{/user}","branches_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/branches{/branch}","tags_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/tags","blobs_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/git/refs{/sha}","trees_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/git/trees{/sha}","statuses_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/statuses/{sha}","languages_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/languages","stargazers_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/stargazers","contributors_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/contributors","subscribers_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/subscribers","subscription_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/subscription","commits_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/commits{/sha}","git_commits_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/git/commits{/sha}","comments_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/comments{/number}","issue_comment_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/issues/comments{/number}","contents_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/contents/{+path}","compare_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/compare/{base}...{head}","merges_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/merges","archive_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/downloads","issues_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/issues{/number}","pulls_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/pulls{/number}","milestones_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/milestones{/number}","notifications_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/labels{/name}","releases_url":"https://api.github.com/repos/feedforce/tech.feedforce.jp/releases{/id}","created_at":"2014-11-28T01:42:34Z","updated_at":"2015-05-07T02:33:06Z","pushed_at":"2015-09-09T01:51:23Z","git_url":"git://github.com/feedforce/tech.feedforce.jp.git","ssh_url":"git@github.com:feedforce/tech.feedforce.jp.git","clone_url":"https://github.com/feedforce/tech.feedforce.jp.git","svn_url":"https://github.com/feedforce/tech.feedforce.jp","homepage":"http://tech.feedforce.jp/","size":16475,"stargazers_count":3,"watchers_count":3,"language":"CSS","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":4,"mirror_url":null,"open_issues_count":4,"forks":4,"open_issues":4,"watchers":3,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/feedforce/tech.feedforce.jp/pulls/121"},"html":{"href":"https://github.com/feedforce/tech.feedforce.jp/pull/121"},"issue":{"href":"https://api.github.com/repos/feedforce/tech.feedforce.jp/issues/121"},"comments":{"href":"https://api.github.com/repos/feedforce/tech.feedforce.jp/issues/121/comments"},"review_comments":{"href":"https://api.github.com/repos/feedforce/tech.feedforce.jp/pulls/121/comments"},"review_comment":{"href":"https://api.github.com/repos/feedforce/tech.feedforce.jp/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/feedforce/tech.feedforce.jp/pulls/121/commits"},"statuses":{"href":"https://api.github.com/repos/feedforce/tech.feedforce.jp/statuses/d5706619ebd93fc049d36b252e8124a30939dc8b"}}}}