ITの隊長のブログ

ITの隊長のブログです。Rubyを使って仕事しています。最近も色々やっているお(^ω^ = ^ω^)

Scala(Template)のif文をOneLinerで記載したときにハマった

要望。DBに登録されている料金を出力したい

ほい

@* db は、Controllerから取得したObject *@
料金:@{db.price} 円

追加要望 とある料金を出力したいだけだったが、ユーザーによっては利用・利用しないってことがあった

なので、条件分岐を用意してあげた。ほい

料金:@if(db.isUse) { @{db.price} 円 } else { 利用しません }

追加要望 料金にカンマ区切りを追加してほしい

ほいさ。

料金:@if(db.isUse) { @{db.price.toString().reverse.sliding(3,3).map( x => x.reverse).toList.reverse.mkString(",")} 円 } else { 利用しません }

エラーが発生いたしました。

Not parsed?

よくわからへん。。。。(´・ω・)?

とりあえず、改行してみることにした

料金:@if(db.isUse) {
    @{db.price.toString().reverse.sliding(3,3).map( x => x.reverse).toList.reverse.mkString(",")} 円
} else {
    利用しません
}

これだとエラーはでない。しかし、、、

料金:
   利用しません

結果が改行されて出力される....! `;:゙;`;・(゚ε゚ )ブッ!!

色々試行錯誤

ifの「{}」を無くしてみる

料金:@if(db.isUse) @{db.price.toString().reverse.sliding(3,3).map( x => x.reverse).toList.reverse.mkString(",")} 円 else 利用しません

エラー。

illegal start of simple expression

ifを「()」で囲めとのお告げがあった。

料金:@(if(db.isUse) @{db.price.toString().reverse.sliding(3,3).map( x => x.reverse).toList.reverse.mkString(",")} 円 else 利用しません)

エラー

Invalid literal number

よくわからん。。。。とりあえず、文字列をHtml("")で囲ってみる

料金:@(if(db.isUse) @db.price.toString().reverse.sliding(3,3).map( x => x.reverse).toList.reverse.mkString(",") + Html("円") else Html("利用しません"))

エラー

type mismatch; found   : Integer required: String

なるほど。StringとIntegerは演算できねぇよってことですね。

料金:@(if(db.isUse) @db.price.toString().reverse.sliding(3,3).map( x => x.reverse).toList.reverse.mkString(",").toString() + Html("円") else Html("利用しません"))

エラー

')' expected but '@' found.

よくわからん。。。。。(´;ω;`)ブワッ

どうやら、@()の中では@はいらないもよう

料金:@(if(db.isUse) db.price.toString().reverse.sliding(3,3).map( x => x.reverse).toList.reverse.mkString(",").toString() + Html("円") else Html("利用しません"))

すると。。。できた!

いまいちよくわかりまてん(^q^)だうー

構文なのかな。。。とりあえずまとめておく。

【NetBeans】CakePHPのShellをデバッグする

PHPではNetBeansを使用しています。

んで、色々使い込んでいますが、Shellでデバッグできないかなと思い、テストしてみたら出来たのでメモ

File -> プロジェクトプロパティを選択

f:id:aipacommander:20150904134530p:plain

実行構成 -> 新規 で、構成を作成します。今回はscriptと名前つけました。

f:id:aipacommander:20150904134554p:plain

そして、下記項目のように設定する。

  • 実行方法:スクリプト(コマンド行で実行)
  • 開始ファイル:/${project_name}/app/Console/cake.php
  • 引数:test-shell dry-run ※これは環境、または実行したいファイル毎に変更してください

f:id:aipacommander:20150904134606p:plain

設定はこれだけ。

あとはデバッグしたいソースにブレークポイント付与とデバッグで実行するだけ。

【CakePHP】アソシエーションで、hasManyとかのconditionsを動的に追加の仕方

とあるアソシエーションが組まれたModelを使って検索。

その際に条件を付与したかった。

関係についてはこんな感じ。

[Info] <= hasOne <= [Post] => hasMany => [PostItemRelation] <= hasMany <= [Item]
  • InfoはPostのidを持っている。
  • PostItemRelationはPostとItemのそれぞれのidを紐付けている

って感じですかね。

んで、Postを使って検索しようとしますよね。 そこで、条件を付与してあげたいのです。

<?php
$this->Post->find('first', array('conditions' => array('Item.name' => '')));

しかし、これだとエラーが発生します。

どうやら、hasManyの場合は一度に検索をするのではなく、2、3回に別けて検索するようです。 なので、初回の検索queryでエラーが発生するというわけ。

  • 最初にPostとInfoを検索(ここではまだItemはでてきていない => エラー!!)
  • PostItemRelationを検索
  • 最後にItemを検索

じゃあどうしましょうか。動的に追加してあげましょう。

<?php

// 動的に追加
$this->Post->hasMany['Item']['conditions'] = array('Item.name' => '');

// 検索
$this->Post->find('first');

// 終わったら戻す(空にする)
$this->Post->hasMany['Item']['conditions'] = array();

これでいけます!

【Play Framework】CSRFの状況でのjQuery append()

jQueryでDomを生成して、htmlソースに追加しようと思って実行

CSRF token not found in body or query string

おうおうおう(^ω^;

github.com

@Override
public F.Promise<Result> call(Http.Context ctx) {
    RequestHeader request = ctx._requestHeader();
    // Check for bypass
    if (CSRFAction.checkCsrfBypass(request, config)) {
        return delegate.call(ctx);
    } else {
        // Get token from cookie/session
        Option<String> headerToken = CSRFAction.getTokenFromHeader(request, config);
        if (headerToken.isDefined()) {
            String tokenToCheck = null;

            // Get token from query string
            Option<String> queryStringToken = CSRFAction.getTokenFromQueryString(request, config);
            if (queryStringToken.isDefined()) {
                tokenToCheck = queryStringToken.get();
            } else {

                // Get token from body
                if (ctx.request().body().asFormUrlEncoded() != null) {
                    String[] values = ctx.request().body().asFormUrlEncoded().get(config.tokenName());
                    if (values != null && values.length > 0) {
                        tokenToCheck = values[0];
                    }
                } else if (ctx.request().body().asMultipartFormData() != null) {
                    String[] values = ctx.request().body().asMultipartFormData().asFormUrlEncoded().get(config.tokenName());
                    if (values != null && values.length > 0) {
                        tokenToCheck = values[0];
                    }
                }
            }

            if (tokenToCheck != null) {
                if (tokenProvider.compareTokens(tokenToCheck, headerToken.get())) {
                    return delegate.call(ctx);
                } else {
                    return handleTokenError(ctx, request, "CSRF tokens don't match");
                }
            } else {
                // ここにひっかかっているっぽい
                return handleTokenError(ctx, request, "CSRF token not found in body or query string");
            }
        } else {
            return handleTokenError(ctx, request, "CSRF token not found in session");
        }
    }
}

そして色々検証してみる。

bodyappend() => エラー!

$('body').append(hiddenInput);

formappend() => エラー!

$('form').append(hiddenInput);

じゃ、じゃあ、idに直接append() => エラー!

$('#hidden_list').append(hiddenInput);

全部だめ! 厳しい! 流石! (´;ω;`)ブワッ

あきらめて、htmlに直書きすることにしました。

【CakePHP】GMO iclusta でSQL文が長いよーってエラーがでたのでそれを解消するためにfindをOverrideした話

ERROR 1104 (42000): The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay

な、なんだこのエラーは。。。

どうやら、MySQLの設定でSQL文が長いとダメらしい。

んで、GMOのiclustaってサービス使っている人はこれに悩まされるとか。

そんな長くないんだけどな。。。このFuピーーーーーーGMO!!!

ということで、問題のsqlを実行する前に下記行を追加するとなおります。

<?php
$this->query('SET SQL_BIG_SELECTS=1');

だがしかし、全部のソースにいれるのは面倒なので、$this->find()をoverrideすることにしました。

  • ~/app/Model/AppModel.php
<?php

class AppModel extends Model {

  /**
   * GMO アイクラスタの環境により、SQL_BIG_SELECTS を 1 にする
   * @override
   */
  public function find($type = 'first', $query = array()) {
    // これを入れると長いSQLでもおk
    $this->query('SET SQL_BIG_SELECTS=1');
    return parent::find($type, $query);
  }
}

これでよし。

【CakePHP】cakeのShellでComponentを呼び出す方法

まずはソースコードから。

<?php

// ライブラリの読み込みを忘れずに
App::uses('ComponentCollection', 'Controller');
App::uses('CSVComponent', 'Controller/Component');

class BatchesShell extends AppShell {

  public $csvComponent = array();

  // startupでComponentを使う準備をする
  public function startup() {
    $collection         = new ComponentCollection();
    $this->csvComponent = new CSVComponent($collection);
    parent::startup();
  }

  /* 省略 */

  /**
   * csv生成
   */
  private function createCSV($array, $contentsArray) {
    // こんな感じで使う
    $this->csvComponent->addRow($array);

    /* 省略 */
  }
}

それでは簡単に説明します。

続きを読む