2011年12月6日火曜日

ActiveAdminをhttpsで使う

Railsの管理画面プラグインActiveAdminで、httpsを使う必要があったので rack_ssl_enforcer というのを使ってみた。

group :production do
gem 'rack-ssl-enforcer', :require => 'rack/ssl-enforcer'
end
view raw Gemfile hosted with ❤ by GitHub
if ENV['RACK_ENV'] == 'production'
AppName::Application.config.middleware.insert_before(ActionDispatch::Cookies, Rack::SslEnforcer, :only => /^\/admin/)
end
2011年12月5日月曜日

deviseでログイン後のリダイレクトはsslを使いたくない場合

deviseを使っていてメールアドレスやパスワードを入力するページは force_ssl をかけていたんだけど、ログイン後のリダイレクトでhttps://hogehoge に飛ばされちゃうと一部の画像とかがssl対応できなかったのでブラウザの判定はイマイチになっちゃう。
そんな時は Devise::SessionsController#create をオーバーライドする

class Users::SessionsController < Devise::SessionsController
# POST /users/sign_in
def create
resource = warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#new")
set_flash_message(:notice, :signed_in) if is_navigational_format?
sign_in(resource_name, resource)
respond_with resource, :location => "http://#{request.host_with_port}#{redirect_location(resource_name, resource)}"
end
end
view raw gistfile1.rb hosted with ❤ by GitHub
2011年11月20日日曜日

jQueryを使用したJavaScriptコーディングスタイル

(function($) {
var elements,
bind = {
buttonClick: function() {
elements.$button.click(e) { e.preventDefault();
action.sayHello('World');
}
}
},
action = {
sayHello: function(to) {
console.log('Hello ' + to + ' !')
}
};
$(function() {
elements = {
$button: $('a.button')
};
bind.buttonClick();
});
})(jQuery);
view raw gistfile1.js hosted with ❤ by GitHub


こんな感じに落ち着いてる。
CoffeeScript覚えるのめんどくさい。
2011年11月10日木曜日

Rails3.1.0 の request オブジェクトのメソッド一覧

[
:ignore_accept_header,
:ignore_accept_header=,
:auth_type,
:gateway_interface,
:path_translated,
:remote_host,
:remote_ident,
:remote_user,
:remote_addr,
:server_name,
:server_protocol,
:accept,
:accept_charset,
:accept_encoding,
:accept_language,
:cache_control,
:from,
:negotiate,
:pragma,
:key?,
:request_method,
:request_method_symbol,
:method,
:method_symbol,
:get?,
:post?,
:put?,
:delete?,
:head?,
:headers,
:fullpath,
:forgery_whitelisted?,
:forgery_whitelisted_with_deprecation?,
:forgery_whitelisted_without_deprecation?,
:media_type,
:content_length,
:xml_http_request?,
:xhr?,
:ip,
:remote_ip,
:server_software,
:raw_post,
:body,
:form_data?,
:body_stream,
:reset_session,
:session=,
:session_options=,
:GET,
:query_parameters,
:POST,
:request_parameters,
:authorization,
:local?,
:cookie_jar,
:flash,
:tld_length,
:tld_length=,
:url,
:protocol,
:raw_host_with_port,
:host,
:host_with_port,
:port,
:standard_port,
:standard_port?,
:optional_port,
:port_string,
:server_port,
:domain,
:subdomains,
:subdomain,
:filtered_parameters,
:filtered_env,
:filtered_path,
:parameter_filter,
:env_filter,
:parameter_filter_for,
:filtered_query_string,
:parameters,
:params,
:path_parameters=,
:symbolized_path_parameters,
:path_parameters,
:content_mime_type,
:content_type,
:accepts,
:format,
:formats,
:format=,
:negotiate_mime,
:valid_accept_header,
:use_accept_header,
:if_modified_since,
:if_none_match,
:not_modified?,
:etag_matches?,
:fresh?,
:env,
:script_name,
:path_info,
:query_string,
:session,
:session_options,
:logger,
:media_type_params,
:content_charset,
:scheme,
:ssl?,
:script_name=,
:path_info=,
:options?,
:patch?,
:trace?,
:parseable_data?,
:[],
:[]=,
:values_at,
:referer,
:referrer,
:user_agent,
:cookies,
:base_url,
:path,
:parse_query,
:parse_multipart,
:psych_to_yaml,
:to_yaml_properties,
:to_yaml,
:in?,
:blank?,
:present?,
:presence,
:acts_like?,
:try,
:html_safe?,
:duplicable?,
:to_json,
:instance_values,
:instance_variable_names,
:as_json,
:with_options,
:to_param,
:to_query,
:`,
:returning,
:dclone,
:require_or_load,
:require_dependency,
:require_association,
:load_dependency,
:load,
:require,
:unloadable,
:nil?,
:===,
:=~,
:!~,
:eql?,
:hash,
:<=>,
:class,
:singleton_class,
:clone,
:dup,
:initialize_dup,
:initialize_clone,
:taint,
:tainted?,
:untaint,
:untrust,
:untrusted?,
:trust,
:freeze,
:frozen?,
:to_s,
:inspect,
:methods,
:singleton_methods,
:protected_methods,
:private_methods,
:public_methods,
:instance_variables,
:instance_variable_get,
:instance_variable_set,
:instance_variable_defined?,
:instance_of?,
:kind_of?,
:is_a?,
:tap,
:send,
:public_send,
:respond_to?,
:respond_to_missing?,
:extend,
:display,
:public_method,
:define_singleton_method,
:__id__,
:object_id,
:to_enum,
:enum_for,
:gem,
:psych_y,
:y,
:silence_warnings,
:enable_warnings,
:with_warnings,
:silence_stderr,
:silence_stream,
:suppress,
:capture,
:silence,
:quietly,
:class_eval,
:require_library_or_gem,
:require_library_or_gem_with_deprecation,
:require_library_or_gem_without_deprecation,
:debugger,
:breakpoint,
:suppress_warnings,
:__called_from__,
:expirable_memoize,
:==,
:equal?,
:!,
:!=,
:instance_eval,
:instance_exec,
:__send__
]
view raw gistfile1.rb hosted with ❤ by GitHub
2011年7月30日土曜日

[Kod][Mac OS X]プログラマー向けエディタKodにhamlとsassのlangファイルが無かった

無かったんです。

なのでrubyとcssで代用しました。(基本的には同じだよね!?)


kod.appコンテキストメニューから「パッケージの内容を表示」で以下のようにフォルダを辿っていくと、「lang」フォルダがあります。


で、haml用にruby.langをコピってhaml.langにリネーム。
でもこれだけだとSyntax modeにRubyが2つになってしまうので、
@titleをHAMLに変更して @matchextをhamlにしておきました。



まぁ色付けは控えめなんだけど……真っ白よりはましかな



scssも同じ要領で使えちゃいますよ!


てゆうかlangファイルの中身ってrubyで書いてあるのね

2011年5月5日木曜日

Mac OS X Snow LeopardでFinder上のファイルパスを右クリックで取得する

というのができない……。なんでですか。


参考:http://linker.in/journal/2010/05/macautomator.php

Mac ローカル環境でWebアプリケーション開発をバーチャルホスト管理にした

↓この記事でMac + XAMPP + eclipseプロジェクトで管理というのを書きましたが、
http://kozo002.blogspot.com/2011/01/cakephp13.html
最近MacBook Airを買ってちょっと環境が変わりましたので書きます。

XAMPPを卒業

Macなんだし。せっかくのUNIX環境と親切にもデフォルトでインストールされているApacheを使うことにしました。
そもそも以前も組み込みのApache使って開発していたのですが、httpd.confをいじってたらよくわからない事態になってしまって……えいや!っとXAMPPに逃げたわけです。はい。

前回の失敗を活かして慎重に進めることにより /Library/WebServer ディレクトリにまとめられました。


バーチャルホストごとに管理

前まではlocalhostのルート直下に site01 とかディレクトリを作って各サイトのトップページにしてたんですが、これ美しくないですよね。というわけで命名規則を local で始まり、サイトの名称をつなげたバーチャルホスト毎に管理するようにしました。例えばブログを開発するなんてときは localblog とかにしてます。

ディレクトリは /Library/WebServer/localblog に app/ と public_html/ を設置。CakePHPの本体は /Library/WebServer/share/cake に置くようにしました。見通しが良くなって気持ちいいです。


バーチャルホストの設定は

  1. /etc/hosts に 127.0.0.1 localblog を追加
  2. 再起動
  3. /etc/apache2/httpd.conf のかなり下の方にある
    # Virtual hosts
    #Include /private/etc/apache2/extra/httpd-vhosts.conf

    ↑をこのように↓修正

    # Virtual hosts
    Include /private/etc/apache2/extra/my-httpd-vhosts.conf

  4. my-httpd-vhosts.confには
    <VirtualHost *:80>
        ServerAdmin sample@gmail.com
        DocumentRoot "/Library/WebServer/Documents"
        ServerName localhost
    #    ServerAlias www.dummy-host.example.com
        ErrorLog "/private/var/log/apache2/localhost.error_log"
        CustomLog "/private/var/log/apache2/localhost.access_log" common
    </VirtualHost>
    
    <VirtualHost *:80>
        ServerAdmin sample@gmail.com
        DocumentRoot "/Library/WebServer/localblog/public_html"
        ServerName localblog
        ErrorLog "/private/var/log/apache2/localblog.error_log"
        CustomLog "/private/var/log/apache2/localblog.access_log" common
        <Directory "/Library/WebServer/localblog/public_html">
            Order deny,allow
            Allow from all
        </Directory>
    </VirtualHost>
    
    と記述しました。

eclipseのプロジェクトもバーチャルホストで管理

これが一番きもちいい結果になりました。今までプロジェクトは cake と app01 と site01 てな感じで一つのサイトを開発してましたが、これが cake と localblog になったので快適です。しかも cake を直接見ることって殆ど無い(ソース上でF3押して出現場所にジャンプするのが便利)ですよね。

以上僕のローカル開発環境でした。

2011年5月3日火曜日

CakePHP 特定のModelだけconfigと違うPrefixを使う

CakePHPもWordPressも超便利だけど、例えばCakePHPで構築したWebアプリに、ニュースとかだけWordPressで投稿できたらいいなぁと思って試してみました。

テーブル名はCakePHPのPrefixが「cake_」でWordPress「wp_」だとします。

そもそも下記のようにやれば、Model自体は自身の名称とちがうテーブルは全然使えるんだけど
class Sample extends AppModel {
  public $useTable = 'example';
}

これだとPrefixが「cake_」前提なんですよね。無理矢理「wp_posts」とか指定すると「cake_wp_posts」で認識されてMissing Tableになっちゃう。

でも何とかできるでしょ〜、と思ってModelのソースをPrefixで検索したらすぐ出てきたww
↓これです。(cake/libs/model/model.phpの2827行目くらい)
function setDataSource($dataSource = null) {
  $oldConfig = $this->useDbConfig;

  if ($dataSource != null) {
   $this->useDbConfig = $dataSource;
  }
  $db =& ConnectionManager::getDataSource($this->useDbConfig);
  if (!empty($oldConfig) && isset($db->config['prefix'])) {
   $oldDb =& ConnectionManager::getDataSource($oldConfig);

   if (!isset($this->tablePrefix) || (!isset($oldDb->config['prefix']) || $this->tablePrefix == $oldDb->config['prefix'])) {
    $this->tablePrefix = $db->config['prefix'];
   }
  } elseif (isset($db->config['prefix'])) {
   $this->tablePrefix = $db->config['prefix'];
  }

  if (empty($db) || !is_object($db)) {
   return $this->cakeError('missingConnection', array(array('code' => 500, 'className' => $this->alias)));
  }
 }

$this->tablePrefix = $db->config['prefix']とかやってますね。このあたりを書き換えちゃえばいいわけで、自分のModel側で以下のようにしてみました。

class News extends AppModel {
 
 var $useTable = 'wp_posts';
 
 public function setDataSource(){
  parent::setDataSource();
  $this->tablePrefix = '';
 }
 
}

これでバッチリWordPress側のデータを取り扱えるはずです。
2011年4月13日水曜日

git導入した

4月に入って弊社にSEのSさんが来るようになった。しかも自分のデスクのとなり。

社内にスクリプトに詳しい人がいなかったのでとても嬉しいことです。(というか一応Webサービスを運営している会社なのにスクリプトを理解している人間が最年少の自分だけって状況は…まじで…どうかしてる)

「バージョン管理とかちゃんとしたほうがいいよ」という空気がむんむんしていたので、じゃあgit入れよう!重い腰を上げたのです。

さてインストールの方法とかは「Mac git インストール」なんかでググればすぐ出てくるし。MacPort入れてgit入れてパス通して〜とかいうのは至極簡単なわけです。わかんないのは使い方ですよ。これが。

Sさんに色々使い方について相談して、作業用のローカルリポジトリ&githubで中央管理という方法に落ち着きました。
というかこれが普通?あ〜はやく慣れたいなぁ。

2011年2月26日土曜日

CakePHPでFacebookにConnectしてみた

日本でも着実にユーザーを増やしているFacebook。いいねボタンが色んなサイトに設置されていますし、某CGMサイトでは自身のコメントシステムを排除してFacebookプラグインに置き換えたり(それまで投稿されたコメント見れなくなった…)と勢いがハンパないです。

そんな激アツなFacebookとCakePHPを連携してアカウントを作成するコントローラーを作成してみました。


  1. まずはオフィシャルのphp-sdkを入手
  2. ゲットしたファイル群をapp/vendorsにfacebookディレクトリを作って丸ごとぶち込む
  3. FacebookControllerを作成(ユーザ情報のテーブルを扱えるならなんでもいい)
さてここからコーディング開始。
まずはメンバ変数$facebookを宣言して、beforeFilter()でインスタンスを生成します。
var $facebook;

function beforeFilter(){
  
    App::import('Vendor', 'facebook/src/facebook');
    $this->facebook = new Facebook(array(
        'appId'  => '123456789123456789',
        'secret' => '123456abcdefghijklmnopqrstuvwxyz',
        'cookie' => true,
    ));
  
}
appIdとsecretは自分で登録したアプリの情報に置き換えてください。
php-sdkのexampleではFBMLとJavascriptを使ってログインボタンを生成してますが、今回は純粋にFacebookController::index()にアクセスしたらFacebookに飛ばされて初回だけ承認する流れにします。
なぜならphp以外の記述がめんどくさいからです!

では以下のようにindex()を用意します。
function index(){
  
    $this->autoRender = false;
  
    $url = $this->facebook->getLoginUrl(array('next' => 'http://localhost/facebook/callback', 'req_perms' => 'email,publish_stream'));
    $this->redirect($url);
 
}
ここで重要なのが$autoRenderにfalseを代入しとかないとリダイレクトしてくれません。ちょっとハマりました。
でgetLoginUrl()メソッドでurlを生成するんですが、引数の連想配列に'req_perms'というキーでアプリからアクセス出来るapiを選べるんです。ユーザ登録に使うのでemailと、あとウォールへ書き込み出来るようにpublish_streamも入れています。ここのページでいろんなapiが確認出来ますよ->Permissions - Facebook開発者

でさらにcallback()を用意します。
function callback(){
 
    $session = $this->facebook->getSession();
    $me = null;
  
    if ($session) {
        try {
            $uid = $this->facebook->getUser();
            $me = $this->facebook->api('/me');
        } catch (FacebookApiException $e) {
            error_log($e);
        }
    }
    $access_token = $this->facebook->getAccessToken();
    $user_data = array(
        'User' => array(
            'username' => $me['first_name'].'.'.$me['last_name'],
            'password' => $this->Auth->password(mt_rand()),
            'email' => $me['email'],
            'other_service_id' => array('facebook' => $me['id'], 'token' => $access_token)
        )
    );
}
承認して戻って来たユーザの$sessionをとって確認して、api('/me')でユーザ情報の部分を叩けば名前とか、性別、言語等がゲット出来ます。ちなみにgetLoginUrl()のreq_permsで指定したemailも$meの中に入ってるんでpr($me)してみるといいと思います。
ここまでできたら$data['User']作成してユーザ登録、ログイン処理という感じなんですがaccessTokenも一緒にDBに保存しておけば以下のコードでウォールへの投稿もできましたよ。

$attachment =  array(
    'access_token' => $access_token,
    'message' => "This is test.",
    'name' => "name test",
    'link' => "http://testtesttesttesttest.com",
    'description' => "here description",
    'picture'=> "http://example.jp/image.jpg"
);
$this->facebook->api('/me/feed', 'POST', $attachment);

こんなかんじで簡単にFacebbokConnectをCakePHPで使えました。
2011年2月15日火曜日

CakePHP viewにelementを埋め込む

WordPressではサイドバーを共通化する場合は(というかブログだから当然サイドバーは共通ですよね)
get_sidebar();

//もしくは定義済みの定数と組み合わせて

include TEMPLATEPATH . '/header2.php';

とか書いたりしますが、CakePHPではどうやるんだろう?とおもってググッてみたら出てきた。
CakePHP View::element() | パン好きのエンジニア
ちょっと違うけど、”View::element()”というメソッドがあった。
Viewの中の一部をelementとして切り出すらしい。

viewフォルダの中を見てみたら確かに /view/element/ というディレクトリがあった。
試しにview内で echo $this->element(); としてみたら読み込むじゃないかァァ
まさに期待通り。

で、データも渡したいなぁと思ってマニュアル見たら
element(string $elementPath, array $data, bool $loadHelpers)
お、二番目に array $data がある。CakePHP的に考えれば、こうゆうときは array('変数名' => '中身') でしょう。と思って試してみたらこれも期待通り!こんな感じでview.ctpからelement.ctpに渡せる
$this->element('sidebar', array('hoge' => 'Hello!'));
もちろんcontrollerでsetした値もそのまま使えるし、繰り返しHTMLパターンがあるなら管理しやすい……と、ここまで書いてて、よく見たら詳しく日本語化されたマニュアルを発見!
http://book.cakephp.org/ja/view/97/Elements
おお!キャッシュも使えるのか♪至れり尽くせりだな。
2011年1月30日日曜日

CakePHPでイラストのギャラリーサイトを作りたい

CakePHPで作るアレとして、題材を考えた。
イラストのギャラリーサイト、要は作家のポートフォリオですね。

ところで以前からWordPressをよく使っていて、というかPHPを始めたのもWordPressを触り始めたからなんだけど、友人のイラストレーターの為に(美術系はマシンに弱い人が多い!)彼のCMSを作ってあげたのがきっかけ。
で、それはもう随分前のことでそろそろリニューアルでもせなあかんなと思っていたのでちょうどいい機会。
CMSとして機能するWebアプリケーションを作ろう思う。

思いつく要件をざっとあげてみよう。

  1. 作品画像がアップできる
  2. 作品にキャプション、サイズ、画材などの情報を付けられる
  3. ユーザが作品にコメントできる
  4. ニュースを投稿できる(個展のお知らせとか)
  5. 作家のプロフィールページ
  6. リンクページ
1、2、4は管理者の機能、3はどうかな…twitterを使うのが今風でいいかもしれない。
4はもしかするとメルマガ的なことが出来るといいのかも。使いこなしてくれるかわからないけどやってみる価値はありそう。
2011年1月29日土曜日

CakePHP1.3勉強中。

とりあえずMVCのControllerとViewの使い方は理解出来た。ここら辺はファイル(*_controller.php と *.ctp)を置くディレクリとアクションの対応とかを覚えるだけだから何回か作ってみれば自然と身に付く。
ただ最初は(フレームワークに触れるのが初めてなのもあるけど)手順がややこしくてちゃぶだいひっくり返したなった…。
要はこうゆうこと

  1. 作りたいページの名前を考える > http://hoge.com/foo
  2. foo_controller.php を app/controllers/ に保存
  3. AppController を継承して FooController クラスを定義する(中身は取りあえず $name $uses index()だけ)
  4. app/views/ にfooというフォルダをつくり index.ctp を作成(中身は空)。

ここまでやれば中身の無いページができる。

つぎに「cake本体」「app」「webroot」をバラバラにして使うやり方も以下を参考にしたら出来た。


自分の環境はMacOSXにXAMPPをインストールして、それぞれのファイル群をeclipseでプロジェクト管理している。(eclipseのワークスペースはxamppのhtdocsに設定)

cake本体を /Applications/XAMPP/xamppfiles/cake に、
appは /Applications/XAMPP/xamppfiles/apps を作成して app1 にした。
あとは htdocs の中に app1 に対応する webroot を配置するだけだけど、これもフォルダ名を app1 とかにしちゃうと eclipse でプロジェクト名がかぶってしまうので、site01 にした。
こうすると http://localhost/site01/~ になるので複数サイトの構築が見やすくていい感じ。
(ちなみに上記の作業をしたら、zipから展開したcakeフォルダに plugin とか vender とか諸々があまってたので全部cake本体と同じディレクトリに入れといた)

さぁこれで準備は整った。なに作ろうかな。