【Rails4】GrapeをつかってAPIを作成する
Grapeとは
REST-likeなAPIを作成する為のフレームワークです。 詳しくは、Grape githubを参照してください。
今回は、サンプルアプリケーションを作成し、jsonを返すAPIを動かしてみます。
サンプルプロジェクトにGrapeをインストール
任意のRailsアプリケーションを作成します。
rails new grape_api --skip-bundle -T
Gemのインストール
作成したアプリケーションのGemfileを編集し、grape
のGemをインストールします。
■ Gemfile
gem 'grape'
bundle install // ※ローカルにインストールする場合は、--path vendor/bundleをつける
ディレクトリを作成する
API経由でデータを参照するために任意のモデルを作成します。
# userテーブルを作成しDBへ反映 rails g scaffold user name:string rake db:migrate
ディレクトリは、下記のような構成にします。
- app - apis - api -v1 - users -vXX
# とりあえず、v1のディレクトリのみ作成 mkdir -p app/apis/api/v1
今回は、上記のファイル構成を元に、
という2つのAPIを作成します。
ファイルの自動インポートの設定を行なう
apisディレクトリ配下に置かれたファイルが自動的にRailsのファイルパスに追加されるようにapplication.rb
を以下のように編集します。
■ config/application.rb
module GrapeApi class Application < Rails::Application # app/api配下の.rbファイルを読み込み対象にする config.paths.add File.join('app', 'apis'), glob: File.join('**', '*.rb') config.autoload_paths += Dir[Rails.root.join('app', 'apis', '*')] end end
APIのパスをルーティングする
APIのルートパスを定義します。
■ config/routes.rb
Rails.application.routes.draw do ・・・ # APIモジュールのBaseクラスを'/'Pathとして定義する mount API::Base => '/' ・・・ end
Baseクラスを作成
ルーティングしたAPI::Base
クラスを定義します。
prefixにapi
を定義することでhttp://[host]/api
のpathを構成することができます。
■ /app/apis/api/base.rb
module API class Base < Grape::API # Baseクラスのpathを定義する prefix 'api' end end
上記のBaseクラスと同じようにv1ディレクトリ配下にもbase.rbを作成します。
version
を定義することでhttp://[host]/api/v1
のpathを構成することができます。
format
でAPIのレスポンスデータのフォーマットをjson
に指定しています。
■ /app/apis/api/v1/base.rb
module API module V1 class Base < Grape::API version 'v1' format :json end end end
先ほど作成したAPI::Base
にAPI::V1::Base
をマウントします。
■ /app/apis/api/base.rb
module API class Base < Grape::API # Baseクラスのpathを定義する prefix 'api' # v1のBaseクラスをマウントする mount API::V1::Base end end
apiクラスを作成
v1
ディレクトリ配下にusersクラスを作成します。
resource
でapiのpathを定義しています。
■ /app/apis/api/v1/users.rb
module API module V1 class Users < Grape::API # `users`resource配下にすることで # /api/v1/usersのapiとしてアクセスできる resource :users do # GET http://[host]/api/v1/users get do User.all end # パラメタバリデーション params do requires :id, {type: Integer, desc: 'user id.'} end # GET http://[host]/api/v1/users/[user_id] get ':id' do User.find(params[:id]) end end end end end
API::V1::Users
をAPI::V1::Base
にマウントします。
■ /app/apis/api/v1/base.rb
module API module V1 class Base < Grape::API version 'v1' format :json end mount API::V1::Users end end
サンプルデータを作成してAPIにアクセス
ローカル環境でRailsサーバを起動します。
rails server
http://localhost:3000/users
にアクセスして、画面上から適当にデータを作成します。
http://localhost:3000/api/v1/users
にアクセスするとUsersテーブルのデータの全件が取得できます。
http://localhost:3000/api/v1/users/1
にアクセスするとUsersテーブルのデータの1件目が取得できます。
参考サイト
http://kzy52.com/entry/2014/11/07/084023 http://qiita.com/hkusu/items/2ca0323cc276ab31e926
【cocos2d-x】【CocoStudio】CocoStudioを使って画面のレイアウトを読み込む
環境
cocos2d-x 3.2
CocoStudio for Mac 1.0.0 Bata
CocoStudioでレイアウトを作成する
まずは、CocoStudioにて任意の画面を作成します。
以下では、画面に一つボタンを置いています。
上記、赤枠の名前
は、各UIパーツのをソースコード上から取得する時に必要になるので、
わかりやすい名前にしておきます。
レイアウトファイルの読み込み
CocoStudioにて、cmd + E
でエクスポート。
[CocoStudioのプロジェクト]/Export配下のに作成したキャンバスのディレクトリが出力されているので、それをそのままXCodeへimportします。
インポートしたレイアウトを以下のようにソースコード上で読み込みます。
#include "cocostudio/CocoStudio.h" // UIパーツを使用するためにimportしておく #include "CocosGUI.h" auto node = cocostudio::timeline::NodeReader::getInstance()->createNode("[jconファイル名]"); // 画面に配置 addChild(node);
子ノードを取得する
レイアウト上に配置した、子ノードを取得するにはgetChildByName()
を使います。
ここで指定するオブジェクト名は、CocoStudio上で名前
に指定した文字列です。
auto button = (Button *)scene->getChildByName("[オブジェクト名]");
階層が深い位置のオブジェクトを取得するには、以下のヘルパーメソッドを使います。
utils::findChildren([探索対象ノード], [オブジェクト名])
Buttonイベントを取得するとき
参考までに、ui::Buttonクラスのタッチイベントを取得するには以下のようにします。
button->addTouchEventListener([&](Ref *ref, Widget::TouchEventType type) { if (type == Widget::TouchEventType::ENDED) { // タッチアップを取得する } });
参考
http://qiita.com/kyokomi/items/9e3dea9325047940f3e0
http://iphone-labo.blogspot.jp/2014/08/cocos2dx-v32node.html
http://giginet.hateblo.jp/entry/2014/08/29/185519
http://raharu0425.hatenablog.com/entry/2014/06/20/154718
【cocos2d-x】cocos2d-x 3.X系を使ってみる① (セットアップ)
最近、ゲーム開発に携わる機会があり、
ゲーム開発の大手プラットホームであるcocos2d-x
について触れてみました。
cocos2d-x
は、2Dゲームをつくることに優れたプラットホームで、
開発の方法はわかり易いのです。
ただ、2.X系と3.X系で大きな違いがあったり、ビルド関連でハマったり色々つまずいたのでメモしておきます。
cocos2d-xのセットアップ
1.ダウンロード
cocos2d-xを以下のページからダウンロードします。
ダウンロードしたcocos2d-xのディレクトリを任意の場所に配置します。
2.setup.pyを実行
手順1でダウンロードしたディレクトリへ移動し、直下にあるsetup.py
ファイルを実行する。
python setup.py
色々と足りないパスを聞かれるので、設定されていないパスがあれば設定を行います。
これで、開発する為の準備が完了しました。
3.新規プロジェクトを作成する
作成するゲームのプロジェクトを作成します。
cocos2d-x 3.X系で新規プロジェクトを作成するには、cocos
コマンドを使用します。
cocos new [プロジェクト名] -p [パッケージ名] -l [開発言語(cpp)] -d [プロジェクトを置くディレクトリ名]
■ 各引数の簡単な解説
-p
Androidプロジェクトのパッケージ名。iOSのBundle identifier
も共通かなと思ってましたが、ここは変わりませんでした。
-l
開発言語を指定します。対応する言語は次のとおりです。 c++ => "cpp", lua => "lua", javascript => "js"
-d
プロジェクトを配置するRootディレクトを指定します
作成されたディレクトリを確認すると、以下のようなディレクトリが作成されているかと思います。
これが各開発環境のプロジェクトディレクトリになります。
proj.android proj.ios_mac proj.linux proj.win32 proj.wp8-xaml
プロジェクトをビルド
プロジェクトが正しく作成できたら、試しにプロジェクトをビルドします。
ここでは、iOS用のプロジェクトをビルドしてみます。
cocos run -s [プロジェクトディレクトリ] -p ios
ビルドが成功すると、iPhoneシュミレータが起動して以下のような画面が表示されているかと思います。
これで、開発のための準備ができました。
今回は、iOS、Androidのアプリをターゲットにしているので、
今後は、各OSでのハマりどころなどを押さえていきたいと思います。
Apache用のVirtualHostの設定メモ(for Mac)
■ 環境
Mac OSX 10.9.3 (Mavericks)
■ Apacheの関連ファイルパス
httpd.conf
/private/etc/apache2/httpd.conf
アクセスログ
/private/var/log/apache2/access_log
エラーログ
/private/var/log/apache2/error_log
各ユーザー設定ファイル
/private/etc/apache2/extra/httpd-userdir.conf
/private/etc/apache2/users/[ユーザー名].conf
1.httpd.confの設定
ユーザーの設定ファイルは、以下のファイルに記述します。
/private/etc/apache2/users/[ユーザー名].conf
設定内容は、以下の通りです。
<VirtualHost *:80> ServerName [ホスト名] DocumentRoot [ドキュメントルートPath] <Directory [ディレクトリパス ※ドキュメントルートと同じ]> Options Indexes FollowSymLinks Includes ExecCGI AllowOverride all Options -MultiViews Order allow,deny Allow from all </Directory> </VirtualHost>
2.hostsの編集
以下のファイルにhostの設定を記載します。
/etc/hosts
127.0.0.1 [ホスト名]
【Android】他のアプリケーションの上にViewを表示する
Androidのアプリの中には、 何かのアプリを起動中もずっと画面上に残り続けるアプリがあると思います。
今回は、上記のように他のアプリケーション上で、
自分のアプリケーションのViewを表示する方法について試して見ました。
Androidのviewは、複数のレイヤーによって構成されており、
通常のアプリケーションのレイヤーは、他のアプリケーションの画面上に乗せることができません。
常に画面上に自分のアプリケーションのViewを表示し、
他のアプリケーションが起動中も自分のアプリのViewを画面上に表示するためには、WindowManager
を使ってレイヤーを指定する必要があります。
通常のアプリケーションの上に載せられるレイヤーには、
幾つか種類がありますが、今回は、画面上のViewに対してタッチイベントを取得したかったので、WindowManager.LayoutParams.TYPE_SYSTEM_ALERT
を使用しました。
※
Androidのレイヤーについては、下記の参考リンクにて詳しく説明されているので、ご参照ください。
使い方は、
以下のようにまずWindowManager
のインスタンスを取得し、
画面上に出したいViewをWindowManagerに対してaddView()
します。
その際に、LayoutParamsにWindowManager.LayoutParams.TYPE_SYSTEM_ALERT
を指定することで、
通常のアプリケーションよりも上にViewを表示することが可能となります。
WindowManager.LayoutParams Params = new WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, // アプリケーションのTOPに配置 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | // フォーカスを当てない(下の画面の操作がd系なくなるため) WindowManager.LayoutParams.FLAG_FULLSCREEN | // OverlapするViewを全画面表示 WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, // モーダル以外のタッチを背後のウィンドウへ送信 PixelFormat.TRANSLUCENT); // viewを透明にする WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); windowManager.addView([OverlapView], mOverlapViewParams);
※
通常のアプリケーションよりも上にViewを表示するため、
使用後は、removeView()
でViewを削除しないと、
画面上にずっと出続けてしまう危険がありますので注意が必要です。
[サンプル]
以下のサンプルでは、
ActivityからServiceをBindし、ServiceからWindowmanagerに対して、
ViewをaddView()
しています。
アプリケーションが終了したタイミングで、
画面上に表示しているViewも一緒に削除されるようにServiceのunbindのタイミングで、
removeView()
を呼び画面からViewを削除しています。
■ OverlapService.java
public class OverlapService extends Service { private WindowManager mWindowManager; private FrameLayout mOverlapView; private WindowManager.LayoutParams mOverlapViewParams; // Serviceに接続するためのBinderクラスを実装する public class LocalBinder extends Binder { //Serviceの取得 OverlapService getService() { return OverlapService.this; } } // Binderの生成 private final IBinder mBinder = new LocalBinder(); @Override public IBinder onBind(Intent intent) { // Service接続時に呼び出される // 戻り値として、Serviceクラスとのbinderを返す。 Log.i("", "onBind" + ": " + intent); return mBinder; } @Override public void onRebind(Intent intent){ // Unbind後に再接続する場合に呼ばれる Log.i("", "onRebind" + ": " + intent); } @Override public boolean onUnbind(Intent intent){ // Service切断時に呼び出される // onUnbindをreturn trueでoverrideすると次回バインド時にonRebildが呼ばれる return true; } @Override public void onCreate() { super.onCreate(); mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); LayoutInflater layoutInflater = LayoutInflater.from(this); mOverlapView = new FrameLayout(getApplicationContext()); ((FrameLayout)mOverlapView).addView(layoutInflater.inflate(R.layout.Overlap_content_view, null)); mOverlapViewParams = new WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, // アプリケーションのTOPに配置 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | // フォーカスを当てない(下の画面の操作がd系なくなるため) WindowManager.LayoutParams.FLAG_FULLSCREEN | // OverlapするViewを全画面表示 WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, // モーダル以外のタッチを背後のウィンドウへ送信 PixelFormat.TRANSLUCENT); // viewを透明にする mWindowManager.addView(mOverlapView, mOverlapViewParams); } @Override public void onDestroy() { // ServiceがunbindされるタイミングでViewも削除して上げる mWindowManager.removeView(mOverlapView); super.onDestroy(); } }
■ MainActivity(呼び出し元)
public class MainActivity extends Activity { // Serviceとのインターフェースクラス private ServiceConnection mConnection = new ServiceConnection() { OverlapService mBindService; public void onServiceConnected(ComponentName className, IBinder service) { // Serviceとの接続確立時に呼び出される。 // service引数には、Onbind()で返却したBinderが渡される mBindService = ((OverlapService.LocalBinder)service).getService(); //必要であればmBoundServiceを使ってバインドしたServiceへの制御を行う } public void onServiceDisconnected(ComponentName className) { // Serviceとの切断時に呼び出される。 mBindService = null; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button bindBtn = (Button) findViewById(R.id.bind_service_button); bindBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent i = new Intent(MainActivity.this,OverlapService.class); bindService(i, mConnection, Context.BIND_AUTO_CREATE); } }); Button unbindBtn = (Button) findViewById(R.id.unbind_service_button); unbindBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // Serviceをunbindする unbindService(mConnection); } }); } @Override protected void onDestroy() { super.onDestroy(); // Serviceをunbindする unbindService(mConnection); } }
(参考リンク)
http://techbooster.org/android/ui/13182/
http://matsuhilog.blogspot.jp/2011/06/typesystemalert.html
初めてのRuby On Rails③ (メールを送る)
Railsには、メールを送信するための仕組みとしてActionMailer
という機能があります。
今回は、ActionMailer
を使用して、Gmailのメール送信を試してみます。
1.環境設定
設定ファイルにGmailの設定を記入します。
config/environments/development.rb
config.action_mailer.default_url_options = { :host => "localhost", :port => 3000 } config.action_mailer.delivery_method = :smtp config.action_mailer.smtp_settings = { :address => "smtp.gmail.com", :port => 587, :domain => 'example.com', :user_name => "[ユーザー名]", :password => "[Gmailのパスワード]", :authentication => 'plain', :enable_starttls_auto => true, }
2.ActionMailerクラスを作成
ActionMailerクラスを生成するには、以下のコマンドを使用します。
rails generate mailer [Mialerクラス名] [アクション名]
例えば、message
というクラスにtest
アクションを定義した場合は、
次のようにコマンドを実行します。
rails generate mailer message test
自動的に以下のファイルが生成されます。
create app/mailers/message.rb invoke erb create app/views/message create app/views/message/test.text.erb create app/views/message/test.html.erb invoke test_unit create test/mailers/message_test.rb create test/mailers/previews/message_preview.rb
ActionMailerクラスは、app/mailers/
配下に作成されています。
app/mailers/message.rb
class Message < ActionMailer::Base # デフォルトの送信もとアドレス default from: "[送信もとアドレス]" # Subject can be set in your I18n file at config/locales/en.yml # with the following lookup: # # en.message.hellp.subject # def hellp @greeting = "Hi" mail to: "[送信先アドレス]" end end
送信されるメッセージの本文は、
app/views/message/test.html.erb
に定義します。
<h1>Message#test</h1> <p> <%= @greeting %>, find me in app/views/message/test.html.erb </p>
3. 送信確認
railsのコンソールからメールを送信してみます。
rails console Message.test.deliver
app/mailers/message.rb
に定義した、
送信先のメールアドレスにメールが送信されていれば、正常に動作しています。
初めてのRuby On Rails② (scaffoldジェネレータ)
Rubyには、コードを自動生成するジェネレータが用意されています。
今回は、データベースのCRUD、
データの作成(Create)、読み出し(Read)、更新(Update)、削除(Delete)
の処理をを自動的に作成してくれる scaffold
ジェネレータを使ってみました。
1.railsプロジェクトの作成
今回は、サンプルとして「bookshelf」というプロジェクトを作成します。
rails new bookshelf
2.scaffoldコマンドの実行
scaffoldジェネレータは、rails generate
から始まるコマンドを使用します。
rails generate scaffold [モデル名] ([カラム名]:[データ型]…)
引数としてモデル名を渡して実行しますが、
ここでオプションとしてカラムを追加することも可能です。
カラムは、[カラム名]:[データ型] の書式で記載します。
今回は、「name」(string)と「description」(text)というカラムを持った「Book」というモデルを作成してみます。
rails generate scaffold Book name:string description:text
以下のように、
関連するモデル、ビュー、コントローラ、テストなどが、自動で生成されます。
invoke active_record create db/migrate/20140603151844_create_books.rb create app/models/book.rb invoke test_unit create test/models/book_test.rb create test/fixtures/books.yml invoke resource_route route resources :books invoke scaffold_controller create app/controllers/books_controller.rb invoke erb create app/views/books create app/views/books/index.html.erb create app/views/books/edit.html.erb create app/views/books/show.html.erb create app/views/books/new.html.erb create app/views/books/_form.html.erb invoke test_unit create test/controllers/books_controller_test.rb invoke helper create app/helpers/books_helper.rb invoke test_unit create test/helpers/books_helper_test.rb invoke jbuilder create app/views/books/index.json.jbuilder create app/views/books/show.json.jbuilder invoke assets invoke coffee create app/assets/javascripts/books.js.coffee invoke scss create app/assets/stylesheets/books.css.scss invoke scss create app/assets/stylesheets/scaffolds.css.scss
まずは、確認のためにhttp://127.0.0.1:3000/books
へ接続してみます。
ActiveRecord::PendingMigrationError
というエラーが表示されました。
これは、rails generate scaffold
コマンドによってプロジェクトの関連ファイルは生成されましたが、
実際のDBのテーブルは、生成されていないため発生するエラーです。
railsがデフォルトで生成されるsqliteDBのファイルを確認しても、テーブルが作成されていないことがわかります。
(dbファイルの場所)
[puroject_path]/db/development.sqlite3
3.DBへマイグレーションファイルを適用する
DBへテーブル情報を反映されるためには、
scaffold
コマンドは、が自動で作成してくれる「マイグレーションファイル」を使います。
「マイグレーションファイル」は、モデルの変更内容をDBへと反映する為の情報が記載されているファイルです。
(マイグレーションファイルの場所)
[puroject_path]/db/migrate/[マイグレーションファイル]
今回は、bookというモデルを作成したので、
[puroject_path]/db/migrate/20140603151844_create_books.rb
というファイルが作成されています。
class CreateBooks < ActiveRecord::Migration def change create_table :books do |t| t.string :name t.text :description t.timestamps end end end
ファイルの中身を見てみるとrails generate scaffold
コマンドで指定したテーブルの、
createメソッドが記述されています。
※ railsでは、モデル名に対して複数型の名称のDBテーブル名をつけるルールになっているため
テーブル名はbooks
となっています。
この、マイグレーションファイルをDBへ反映されるためには、
以下のコマンドを実行します。
rake db:migrate
先ほど確認したsqliteDBファイルを再度確認すると
books
というテーブルができていることが確認できます。
sqlite> .tables books schema_migrations sqlite>
もう一度http://127.0.0.1:3000/books
へ接続し表示を確認すると、
エラーが消え以下のような画面が表示されます。
画面から、New Book
のリンクをクリックすると以下のような画面へ遷移し、
booksテーブルにレコードを追加することができます。
その他、レコードの編集など、
基本的なデータ操作をscaffoldジェネレータを使うだけで簡単に実装することが可能です。