Rails 4.2 で Heroku にデプロイしたメモ
はじめに
- Rails 4.2 で開発していたアプリを Heroku にデプロイした時にやったことメモ
Heroku にユーザー登録
- 済
Heroku アプリの作成
$ cd /path/to/rails/app
$ heroku create
Heroku 用の gem の追加
$ vi Gemfile
-gem 'sqlite3' +gem 'sqlite3', :group => [:development, :test] +gem 'pg', :group => [:production] # heroku で DBMS として PostgreSQL を使用するために必要 +gem 'rails_12factor', group: :production # heroku で Rails 4 を動かすために調整してくれるやつ
$ bundle install --without production
Devise の設定
- Devise を使っている場合
$ vi config/initializers/devise.rb
config.secret_key = '<%= ENV["DEVISE_SECRET_KEY"] %>' if Rails.env.production?
heroku config:add DEVISE_SECRET_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
データベースの設定
$ vi config/database.yml
production: adapter: postgresql encoding: unicode pool: 5
シークレットキーの設定
- シークレットキーを環境変数から読み込むように
$ vi config/secrets.yml
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
- .gitignore に config/secrets.yml が登録されている場合は削除する
デプロイ
$ git commit -am 'for heroku' $ git push heroku master $ heroku run rake db:migrate
Rails 4.2 で destroy のバリデーションをする
任意の条件でバリデーションをする
- http://qiita.com/tbaba/items/9ea139dc77443e6d7be2 の通り、before_destroy に指定したメソッド内で条件を判定し、destroy 不可であれば return false する
- 前記記事の通り before_destroy :method_name の記法ではなく、before_destroy do ... end で宣言すると、return false 時に LocalJumpError の例外が発生して意図したように動作しなくてはまった
関連レコードがある場合は destroy できないように
- バリデーションの条件として、関連するレコードがあったら destroy 出来なくしたいだけの場合は has_meny のオプションだけで対応できる
models
has_many :associate_name, dependent: :restrict_with_error # has_many のその他のオプション # http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many
controllers
if @result = @obj.destroy # 成功 else # 失敗 end
Unity Ads 導入メモ
やったこと
- Unity Ads のサイトにアカウント登録
- Unity Ads でアプリの登録とID取得
- Asset Store から Unity Ads のインポート
- 広告の呼び出しスクリプトの作成と実行
参考サイト
スクリプト例
AdsManager
using UnityEngine; using System.Collections; using UnityEngine.Advertisements; public class AdsManager : MonoBehaviour { void Awake() { if (Advertisement.isSupported) { Advertisement.allowPrecache = true; Advertisement.Initialize (Config.unityAdsId, true); } else { Debug.Log("Platform not supported"); } } public void Show() { Advertisement.Show(null, new ShowOptions { pause = true, resultCallback = result => { Debug.Log("広告閲覧終了。広告閲覧報酬を付与するならここで。"); Debug.Log(result.ToString()); } }); } }
Config
using UnityEngine; using System.Collections; public class Config { #if UNITY_IPHONE public static string unityAdsId = "iOSアプリのID"; #elif UNITY_ANDROID public static string unityAdsId = "AndroidアプリのID"; #endif }
広告表示
GameObject.FindObjectOfType<AdsManager>().Show();
MagicalRecord で Date の範囲検索
- Entity エンティティの creationDate 属性に作成日時が入っているものとして、今日作成されたデータを取得する場合
// 今日の0時0分0秒を取得 NSCalendar* calendar = [NSCalendar currentCalendar]; unsigned int flags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay; NSDateComponents* components = [calendar components:flags fromDate:[NSDate date]]; NSDate* fromDate = [calendar dateFromComponents:components]; // 明日の0時0分0秒 NSDate* toDate = [fromDate dateByAddingTimeInterval:60*60*24]; // 検索条件の作成と実行 NSPredicate* p = [NSPredicate predicateWithFormat:@"(creationDate >= %@) AND (creationDate < %@)", fromDate, toDate]; Entity* entity = [Entity MR_findFirstWithPredicate:p];
MagicalRecord を試したメモ
はじめに
- iOS アプリ開発で ActiveRecord ライクに CoreData を扱うことが出来る MagicalRecord を試したメモ
- CocoaPod を使うのも初めてなのでそこもちょっと詳しく
動作環境
- XCode 6.1.1
- MagicalRecord 2.2
- mogenerator 1.27
参考URL
CoreDateの用語
- 管理オブジェクト(NSManagedObject) : レコード
- 管理オブジェクトコンテキスト(NSManagedObjectContext) : ORM
- 管理オブジェクトモデル(NSManagedObjectModel) : スキーマ
プロジェクトの作成
- "Use Core Data" にチェックを入れて作成
MagicalRecord のインストール
CocoaPod のインストール
- インストールしていなければ
sudo gem install cocoapods
MagicalRecord のインストール
# cd /path/to/xcode/project # /usr/bin/pod init # vi Podfile
target 'ProjectName' do pod "MagicalRecord" pod "MagicalRecord/Shorthand" end
# /usr/bin/pod update
MagicalRecord を読み込む
- pod update によって CocoaPods が有効な状態の XCode プロジェクトファイル(APPNAME.xcworkspace)が生成されているので、これを開く
# open App.xcworkspace
エンティティ(テーブル)の追加
- APPNAME.xcdatamodeld ファイルを選択
- "Add Entity" ボタンでエンティティの作成
- 画面右のインスペクタで Entity の Name と Class を設定 (Class はクラスファイル生成時に必要)
- エンティティを選択して "Add Attribute" ボタンでアトリビュート(カラム)の作成
リレーションシップについて
- http://qiita.com/yuiseki/items/33ec35ec99b5304be90a
- Auther エンティティと Book エンティティが 1:多 の関係になるとする
- Auther の設定
- Auther の Relationships で "+" を押下しリレーションシップを作成
- Relationships を books
- Destination を Book
- Inverse はとりあえずそのまま(Book 側の Inverse を設定すれば自動でセットされる)
- Auther の books を選択した状態のインスペクタで、Relationships の Type を "To Many" に
- 同じく "Delete Rule" を "Cascade" にすると Auther 削除時に関連する Book も削除されるので任意で設定
- Auther の Relationships で "+" を押下しリレーションシップを作成
- Book の設定
- Book の Relationships で "+" を押下しリレーションシップを作成
- Relationships を auther
- Destination を Auther
- Inverse は books
- Book の auther を選択した状態のインスペクタで、Relationships の Type を "To One" に
- Book の Relationships で "+" を押下しリレーションシップを作成
カスタム管理オブジェクトクラスの作成
mogenerator のインストール
# brew install mogenerator # /usr/local/bin/mogenerator -v
ファイルの作成
# /usr/local/bin/mogenerator -m Model.xcdatamodeld/Model.xcdatamodel -O CoreData/ --template-var arc=true
MagicalRecord の初期化
AppDelegate.h
#import <MagicalRecord.h> #import <MagicalRecord+Setup.h>
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [MagicalRecord setupCoreDataStackWithAutoMigratingSqliteStoreNamed:@"app.db"]; // 追記 return YES; } - (void)applicationWillTerminate:(UIApplication *)application { [MagicalRecord cleanUp]; // 追記 }
MagicalRecord を使う
ViewController.h
- Auther.h, Book.h はカスタム管理オブジェクトクラス
#import <CoreData/CoreData.h> #import <CoreData+MagicalRecord.h> #import "Auther.h" #import "Book.h"
ViewController.m
- (void)viewDidLoad { [super viewDidLoad]; // Auther の作成 Auther* auther = [Auther MR_createEntity]; auther.name = @"Neal Stephenson"; // Book の作成と Auther との関連付け Book* book1 = [Book MR_createEntity]; book1.title = @"Snow Crash"; [auther addBooksObject:book1]; Book* book2 = [Book MR_createEntity]; book2.title = @"The Diamond Age"; [auther addBooksObject:book2]; Book* book3 = [Book MR_createEntity]; book3.title = @"Cryptonomicon"; [auther addBooksObject:book3]; // 作成したレコードの登録 [[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreAndWait]; // Auther の一覧を取得 NSArray* array = [Auther MR_findAll]; int i = 0; NSLog(@"Count:%lu", (unsigned long)[array count]); for (Auther* a in array) { NSLog(@"#####%d name=%@", i, a.name); // Auther に関連付いた Book の取得 for (Book* b in a.books) { NSLog(@"----- title=%@", b.title); } i++; } // 削除 [auther MR_deleteEntity]; [[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreAndWait]; }
iOSアプリ開発チュートリアルメモ
ナビゲーションコントローラの追加
- タイトル表示や戻るなどが出来るようになる
- 追加したいビューコントローラを選択した状態で、メニューから Editor > Embed In > Navigation Controller
カスタムコントローラの追加
ボタン押下で遷移
- Storyboard でビューコントローラにボタンの追加
- ボタンを右クリック Touch Up Inside からドラッグして遷移先のビューコントローラでドロップ
戻る遷移とコールバックの登録
ビューの要素をコントローラにひもづける
- 右上の Show the Assistant Editor (蝶ネクタイのアイコン) をクリックして Storyboard とコントローラのソースを表示
- Storyboard で要素を右クリック、Referencing Outlet をコントローラの @interface セクションにひもづける
プロパティを宣言する
- public なら .h の @interface で
- private なら .m の @interface で
- 記法は @property (オプション) 型 プロパティ名;
- オプション
- readonly : 読み込み専用
- プロパティの初期値は nil
メソッドの宣言
遷移前実行メソッド
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if (sender != self.doneButton) return; if (self.textField.text.length > 0) { self.toDoItem = [[XYZToDoItem alloc] init]; self.toDoItem.itemName = self.textField.text; self.toDoItem.completed = NO; } }
テーブル関連
セクション数を返すメソッド
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { #warning Potentially incomplete method implementation. // Return the number of sections. return 0; }
アイテム数を返すメソッド
- 例は配列の要素数を返す
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // Return the number of rows in the section. return [self.toDoItems count]; }
ポジション毎にアイテムをセットするメソッド
- 例は配列から対応する要素を取得してテキストにセットしている
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"ListPrototypeCell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; XYZToDoItem *toDoItem = [self.toDoItems objectAtIndex:indexPath.row]; cell.textLabel.text = toDoItem.itemName; return cell; }
ドキュメントを見る
- Help > "Documentation and API Reference"
ActiveAndroid Tips
はじめに
- 基本的な使い方は以下のページにまとまっていたので、その他のTipsをメモ。
Date型を扱う
- SQLite では Date 型が扱えないので、Long に変換して利用するため、http://dev.classmethod.jp/smartphone/android/activeandroid/ にあるシリアライザーを使う。
- Search の条件で Date 型を指定する場合は、シリアライザーが効かないので都度自分で変換する。
Date now = new Date(); new Select() .from(SomeModel.class) .where("SomeDate = ?", now.getTime()) .execute();
リレーションシップ
"1:多"な親子関係の定義
- Category が親で Item が子
@Table(name = "Categories") public class Category extends Model { @Column(name = "Name") public String name; public List<Item> items() { return getMany(Item.class, "Category"); } } @Table(name = "Items") public class Item extends Model { @Column(name = "Name") public String name; @Column(name = "Category") public Category category; }
外部キー制約で親の削除時に子も削除する
- デフォルトでは子のいる親を削除すると例外が発生する
- Column の定義時に onDelete を適宜指定すると、子も同時に削除できる
@Table(name = "Items") public class Item extends Model { @Column(name = "Name") public String name; // 変更箇所 @Column(name = "Category", onDelete = Column.ForeignKeyAction.CASCADE) public Category category; }
レコードの存在確認
- 検索したレコードが存在するか確認したい場合は、execute() で結果の List の要素数を調べるか、exists() を使う。
public void testExistsWhereClause() { cleanTable(); populateTable(); From from = new Select() .from(MockModel.class) .where("intField = ?", 1); final List<MockModel> list = from.execute(); final boolean exists = from.exists(); assertTrue(exists); assertTrue(list.size() > 0); }