ラベル rails の投稿を表示しています。 すべての投稿を表示
ラベル rails の投稿を表示しています。 すべての投稿を表示
2013年6月15日土曜日

[Rails3] サイドバーの実装には Cells が便利

RailsでViewを作りこんでいくと、ifやeach、さらに変数を代入するだけの行とか出てきてしまってあまり綺麗なViewではなくなっていくとこがよくある。
ifとか文字列の連結を省略したいだけなら ActiveDecorator とかが便利

↑こうゆうやつ

でもブログのサイドバーみたいにサイト全体で使うViewがあったりすると、

  • データはControllerで用意するの? => before_filter使うとか
  • Viewから直接Modelは呼び出したくないよね。。
  • そもそもViewファイルはどこに置けばいいんだろ? => views/layouts/_sidebar.html.erbとか?
  • SidebarControllerを実装してサイドバーだけajaxでhtmlを取得するとか?

いろいろモヤモヤするとこがあって、あんまり最適解じゃない気がする。

でも Cells というgemを使うとViewの部品を小さなコントローラのような形で実装できるようになるのでスッキリ綺麗に書けて凄くイイネ!

インストール

Gemfileに以下を書いてbundle installするだけ

Gemfile

+ gem 'cells'
$ bundle install

ジェネレート

インストールするとジェネレータが追加されているので、cellの名前とアクション名を渡して作成出来る

$ bundle exec rails g cell sidebar show

ERB以外のテンプレートを使う場合は -e オプションを指定すればOK

$ bundle exec rails g cell sidebar show -e haml

生成したCellは app/cells にある

app
├── cells
│   ├── sidebar
│   │   └── show.html.haml
│   └── sidebar_cell.rb

使ってみる

Cellを埋め込みたいViewの部分に render_cell を使うとレンダリングされる。引数は Cell名, アクション名

Cellの中では普通にModelが呼べるので

こんなかんじでModelからデータを受け取ってインスタンス変数に入れておけばCellのViewで使えるようになる

render_cellには3番目の引数があって、ここに渡したものはCellのアクションメソッドの引数に入るようになる

もう少し便利に

このままだと通常のViewで使えるヘルパーメソッドは一切呼べないので、ApplicationCell を作って継承するようにしてる。

helperというメソッドに使いたいヘルパーのモジュールを渡すと使えるようになる

また helper_method というメソッドも用意されていて、個別にヘルパーを追加できるようにもなってる。
自分はdeviseの current_user をCellのViewでも使いたかったので以下のようにしてみた

これで c.current_user とすれば呼び出せて、ログインしてたら編集ボタンを表示するようにできた

以前はSidebarControllerを実装してサイドバーのhtmlだけajaxで取得とかやってたこともあるけど、そもそもjsがオフってあると使えないし、Controllerはアプリケーションのリソースのためだけに使うようにしたいからこの方法がベストだと思う。
railsに取り込まれてもいいんじゃないかなぁ

2013年6月14日金曜日

[Rails3] has_many through で polymorphic な関連で相互に参照する

Rails3で has_many through でしかも polymorphic な関連を実装していて、polymorphicなモデル側からhas_manyを探せるけど、逆のやり方に苦戦したのでメモ

User モデルは複数の Clubに属すことができて、Clubもまた複数の Userを受け入れられるという感じ。

最初にやってた方法

Membership はpolymorphicなモデルにしていて、例えばClub以外にもFamilyとか他のグループでも同じモデルを使いまわしたかった。

データを作ってみる

rails consoleでデータを作成

user = User.create({ name: 'kozo' })
=> #<User id: 1, name: "kozo", created_at: "2013-06-14 03:14:59", updated_at: "2013-06-14 03:14:59">
club = Club.create({ name: 'football' })
=> #<Club id: 1, name: "football", created_at: "2013-06-14 03:14:50", updated_at: "2013-06-14 03:14:50">

club.memberships.create({ user_id: user.id })
=> #<Membership id: 1, user_id: 1, membable_id: 1, membable_type: "Club", created_at: "2013-06-14 03:15:19", updated_at: "2013-06-14 03:15:19">

Club -> Userの参照はうまくいく

こんな感じにClub側からUserを参照するのは簡単にできちゃう

club = Club.find(1)
club.members
# =>[#<User id: 1, name: "kozo", created_at: "2013-06-14 03:14:59", updated_at: "2013-06-14 03:14:59">]

User -> Clubの参照はできなかった・・・

user = User.find(1)
user.membered_clubs
# => ActiveRecord::HasManyThroughSourceAssociationNotFoundError: 
 Could not find the source association(s) :membable in model Membership.
 Try 'has_many :membered_clubs, :through => :memberships, :source => <name>'. Is it one of :user or :club?

ドキュメントにはsourceとsource_typeを使えばOKって書いてあるっぽい

ruby/rails/RailsGuidesをゆっくり和訳してみたよ/Active Record Associations - 株式会社ウサギィwiki

4.3.2.18 :source

:source オプションは has_many :through アソシエーションの元になるアソシエーション名を指定します。 元のアソシエーションの名前が自動的にアソシエーション名から推測できない場合にのみ、このオプションを使用する必要があります。

4.3.2.19 :source_type

:source_type オプションは polymorphic アソシエーションを通じて進める has_many :through アソシエーションの元になる型を指定します。

でもググったらすぐ出てきた

has_many :through - The other side of polymorphic :through associations

MembershipとUserに細かく書いてあげるといいっぽい

club = Club.find(1)
=> #<Club id: 1, name: "football", created_at: "2013-06-14 03:14:50", updated_at: "2013-06-14 03:14:50">
club.members
=> [#<User id: 1, name: "kozo", created_at: "2013-06-14 03:14:59", updated_at: "2013-06-14 03:14:59">]

user = User.find(1)
=> #<User id: 1, name: "kozo", created_at: "2013-06-14 03:14:59", updated_at: "2013-06-14 03:14:59">
user.membered_clubs
=> [#<Club id: 1, name: "football", created_at: "2013-06-14 03:14:50", updated_at: "2013-06-14 03:14:50">]

できた!

2012年8月20日月曜日

Rails3でクエリパラメータでルーティング(Advanced Constraints)

少し前にsendagaya.rbで発表したRails3のAdvanced Constraintsをここでも紹介。

routes.rbの中でURLを定義する時にsubdomainとかを条件に含めるときに使うのがconstraintsというオプションなんですが、これを使ってURLの「?」以降を条件にしたりもできます。

方法はrequestオブジェクトを受け付けるmatches?というメソッドを実装したクラスを定義してインスタンスをconstraintsに渡してあげるだけです。

ここではpostというリソースの集合であるindex、つまり /posts というURLにGETで ?q=hoge 等のパラメータが付いている時に posts_controller#search というアクションに紐付けるということを行なっています。

ただしこのままだと q に対するvalueが空の状態 /posts?q でもsearchアクションに処理が渡るので、コントローラ側で何かしらの対応が必要です。

基本的にはrequestオブジェクトを使って判別できるならどんな条件でもいいので、Accept-languageで振り分けるとかIPアドレスでブラックリストを作るとかもできてしまいます。

今回はindexアクションの中でifで分岐させておくことでも十分対応可能ですが、render以外はほとんど共通処理がないよとかになると、アクションそのものを分けてしまったほうが綺麗なコードになりそうですよね。

2012年7月6日金曜日

CentOS 6 でRails + thin + nginxを動かした

thinってオワコンじゃないですよね?herokuで採用されているし別にいいですよね。
本当はunicorn使いたかったんですが難しい…… ><;
ぐぐると記事沢山出てきますが uninitialized constant errorで起動しない問題が解決できなくてやめちゃいました。いつかリベンジします。

CentOS 6

マシンはvagrant使ってcentos6を用意しました。
参考:http://www.ryuzee.com/contents/blog/4292
vagrantって便利ですね。元々Virtual Boxでwindows動かしてたのですんなりです。ホントに。するっと。

IPアドレスと

config.vm.network :hostonly, "192.168.33.10"

メモリとnameを設定しておきました

config.vm.customize do |vm|
  vm.memory_size = 1024
  vm.name = 'vagrant_centos6'
end

Ruby

rbenv + ruby-buildで1.9.3-p194をインストール

Thin

Gemfileのgroup :productionにgem 'thin'を追加して普通にbundle install

config/thin.ymlは

pid: tmp/pids/thin.pid
log: log/thin.log
servers: 1
port: 3000
daemonize: true
environment: production
user: vagrant
group: staff

以下で起動、停止、再起動

$ be thin start|stop|restart -C config/thin.yml

Nginx

yumでnginxをインストール(参考:http://blog.livedoor.jp/sasata299/archives/51810645.html

/etc/nginx/nginx.confは

worker_processes  1; 

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    gzip  on;

    # include /etc/nginx/conf.d/*.conf;

    upstream backend {
        server localhost:3000;
    }
    upstream backend2 {
        server localhost:3001;
    }
    server {
        listen 80;
        server_name centos6.vag;
        location / {
            proxy_pass http://backend;
        }
    } 
    server {
        listen 80;
        server_name 2.centos6.vag;
        location / {
            proxy_pass http://backend2;
        }
    } 
}

試す

あとはmacのhostsに

192.168.33.10 centos6.vag
192.168.33.10 2.centos6.vag

を設定してブラウザでアクセス!

サクセス!

でもnginx.confの書き方冗長だなぁもっといいのあるんだろうか。

※追記

上記の状態で試しに request.url を覗いてみたら http://backend2/ とかでちゃったよ!困るよ!

というわけでnginx.confを一部修正してみたら問題なく動いた

    ...省略...
    upstream 2.centos6.vag {
        server localhost:3001;
    }
    server {
        listen 80;
        server_name 2.centos6.vag;
        location / {
            proxy_pass http://2.centos6.vag;
        }
    }
    ...省略...

request.url でhttp://2.centos6.vagが返ってきた!

※追記2

画像など静的ファイルが返らないことがわかったので以下のようにconfig修正

    server {
        listen 80;
        server_name 2.centos6.vag;

        proxy_set_header    X-Real-IP       $remote_addr;
        proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header    Host            $http_host;
        proxy_redirect      off;
        proxy_max_temp_file_size    0;

        location ~ .*\.(jpg|JPG|gif|GIF|png|PNG|swf|SWF|css|CSS|js|JS|inc|INC|ico|ICO) {
            root /home/vagrant/sample2/public;
            ssi  on;
            break;
        }

        location / {
            proxy_pass http://2.centos6.vag;
        }
    }

※追記3

thinの再起動などダウンタイムにnginxのデフォルトエラーページが返されるのでconfig追加

     error_page   500 502 503 504  /500.html;↲
        location = /500.html {↲
        root   /home/vagrant/sample2/public;↲
     }

※追記4

マシンを再起動したときにthinも自動起動するようにした!

/etc/init.d/sampleを作成

#!/bin/sh
# chkconfig: 2345 86 25
# description: Sample
#

PATH=/home/vagrant/.rbenv/shims:/home/vagrant/.rbenv/bin:$PATH
eval "$(rbenv init -)"

APP_DIR=/home/vagrant/sample
THIN_CONFIG=$APP_DIR/config/thin.yml

case $1 in
  start)
  cd $APP_DIR
  bundle exec thin start -C $THIN_CONFIG
  ;;
  stop)
  cd $APP_DIR
  bundle exec thin stop -C $THIN_CONFIG
  ;;
  restart)
  cd $APP_DIR
  bundle exec thin restart -C $THIN_CONFIG
  ;;
esac

exit 0

登録する

$ sudo /etc/init.d/sample start
$ sudo chkconfig sample on

2012年6月1日金曜日

CoffeeScriptでJavaScriptもクラス化しよう。テストを書きやすくメンテしやすく

CoffeeScriptを知ったのはRailsに組み込まれたからですが、Rails3.1で採用されてすぐに飛びついたわけではなく、しばらく敬遠してた時期もありました。しかし使い始めてからはもう手放せなくなりました。
そして次第にCoffeeScriptのclass構文を使えばよりよいJavaScriptの開発ができるのではないかと思うようになりました。
今回は最近CoffeeScriptを使ってどのように開発しているかを紹介したいと思います。

CoffeeScriptでのclass定義はこうやります

class Person
  constructor: (@my_name) ->

  greeting: ->
    alert "Hello! my name is #{@my_name}."

window.Person = window.Person || Person

コンパイルすると以下のようなJavaScriptになります

(function() {
  var Person;

  Person = (function() {

    Person.name = 'Person';

    function Person(my_name) {
      this.myname = my_name;
    }

    Person.prototype.greeting = function() {
      return alert("Hello! my name is " + this.my_name);
    };

    return Person;

  })();

  window.Person = window.Person || Person;
}).call(this);

※nameプロパティを使うと上書きしてしまうのでmynameとしました

例えばこのようなコードを person というファイル名で保存し、インスタンス生成は main という別ファイルで実行します。

main.coffee
$ ->
  kozo = new window.Person 'kozo'
  kozo.greeting()
main.js
(function() {
  $(function() {
    var kozo;
    kozo = new window.Person('kozo');
    return kozo.greeting();
  });
}).call(this);

こうすることでまず管理がしやすくなりますし、テストも気持ちよく書けると思います。

テストフレームワークはよく jasmine をつかっています。その前は QUnit だったんですが jasmine の方がドキュメントが探しやすいのとツールが整っている印象ですし、なによりコードが書きやすく後からでも見やすいですね。人によるかも知れませんが。
僕の場合CoffeeScript を使うときはほぼ Rails か sinatra 上ですので jasmine-headless-webkit というgemをつかってます。これを使うとCUIで実行結果が得られます。(jasmine-railsはこれに依存しています)

jasmineの諸々の設定は省略しますがテストコードはこんな感じにしています。

person_spec.coffee
describe "Person", ->

  beforeEach ->
    @person = new window.Person 'sample'

  afterEach ->
    delete @person

  describe "propaties", ->
    it "have 'my_name' string", ->
      expect(typeof @person.my_name).toBe "string"

  describe "greeting method", ->
    beforeEach ->
      spyOn window, "alert"
      @person.greeting()

    it "alert greeting text", ->
      expect(window.alert).toHaveBeenCalledWith "Hello! my name is sample."

DOMが絡むテストは jasmine-fixture というのをhelperとして読み込んで使っています。jqueryに依存しているのですが、むしろ使わない事のほうが少ないので気にしないです。affix という便利メソッドが使えるようになって、jqueryオブジェクトのprototypeにも追加されるので気に入ってます。

以上のような形で開発を進めてるのですが、クラスファイルと実行ファイルを分けてなるべくDOMの情報とかは実行ファイルに書き込むようにするといいと思います。
サイトのトップページにスライドショー的なものを設置するなら例えば以下の様な感じです。

main.coffee
$ ->
  slideshow = new window.Slideshow {
    container_id: '#hoge-slideshow'
    controller_id: '#hoge-controller'
    duration: 800
    wait: 3000
  }
  slideshow.start()

要はリテラル値をまとめて書いておくということです。

ただこのように実行ファイルに分けていてもファイル名が script とかにする人がいたりして…それはそれでわからなくはないのですが、mainの方が無難じゃないですかねぇ。

あぁマシン持ち寄ってこうゆう話ししながら酒を呑む仲間がほしいなぁ…

2012年5月2日水曜日

railsのform_forに渡すモデルオブジェクトでurl生成する場合の話

railsのform_forヘルパーは以下のように使いますよね

= form_for(@post) do |f|
  = f.label :title
  = f.text_field :title

こう書いておけば出力されるhtmlは

大体こんな感じになるかと。
でrailsの便利なところはform_forに渡してるモデルオブジェクトが、空なのかDBのレコードから生成されたのかを判別して、actionの属性値をよしなに変更してくれるところですよね。

つまりroutesに

resouces :posts do
end

と書いてあれば 新規作成時は action="/posts" だし編集画面では action="/posts/1" になると。 でもこれが namespace 付きのroutesだとうまく行かなくて困りました。
管理画面を作る場合とかだと /admin/posts にしたくて

namespace :admin do
  resources :posts do
  end
end

と定義しておいて、form_for で生成したフォームを上記のままにしておくと、undefined method `posts_path' と怒られてしまう。 一瞬下記のやり方?とか思ったんですがrailsに限ってそんなことないよね…

= form_for params[:action] == 'new' ? admin_posts_path : edit_admin_post_path(@post) do |f|
  = f.label :title
  = f.text_field :title

ぐぐったら出てきた。

Rails Routes Namespaces and form_for - Stack Overflow
= form_for [:admin, @post] do |f|...

だってさ!
配列で指定するんですか。なるほどこれで admin_posts_path と edit_admin_post_path を切り替えてくれるんですね。

ということは…やってみた。

namespace :hoge do
  namespace :fuga do
    namespace :foo do
      namespace :bar do
        resources :hellos do
        end
      end
    end
  end
end
= form_for [:hoge, :fuga, :foo, :bar, @hello], do |f|
  = f.label :name
  = f.text_field :name

成功\(^o^)/

2012年4月27日金曜日

[ruby]最初に知っておけば良かったbundlerの使い方 sinatra編

rails編は以前書いたのでsinatraでやってみる
用途としてはDBとかいらないスタティックなサイトの構築で、でもhtml、css、jsを生で書くのとか耐えられない。phpはマジ勘弁みたいなときにこうしてますよって感じのことを書きます。

(bundlerの使い方ってゆうかrubyでのweb制作全般って感じですね…)

まず適当な場所にプロジェクトのディレクトリを作ります。
hogeとかもアレなんでポートフォリオにしときます。

$ cd ~/Web
$ mkdir portfolio
$ cd portfolio

でプロジェクトのルートでGemfileをつくる

$ bundle init
Writing new Gemfile to /Users/kozo/Web/portfolio/Gemfile

中身はこんな感じだから...

$ vim Gemfile
# A sample Gemfile
source "https://rubygems.org"

# gem "rails"

以下に書き換えます

source "https://rubygems.org"

gem "sinatra"
gem "sass"
gem "haml"
gem "coffee-script"
gem "shotgun"

自分はnode.jsを入れてるんでアレですが、環境によってはjavascript実行環境が無いと怒られるかもしれないんで、そんときは以下のgemを足してみてください。

gem 'therubyracer'

でgemをインストールします。

bundle install --path vendor/bundle --without production

Fetching gem metadata from https://rubygems.org/.....
Installing coffee-script-source (1.3.1) 
Installing multi_json (1.3.2) 
Installing execjs (1.3.0) 
Installing coffee-script (2.2.0) 
Installing haml (3.1.4) 
Installing rack (1.4.1) 
Installing rack-protection (1.2.0) 
Installing sass (3.1.16) 
Installing tilt (1.3.3) 
Installing sinatra (1.3.2)
....

よしこれでgemが揃いました。
さらに作業環境を整えます。

sinatraを動かすアプリが必要なので app.rb と config.ru
sassやhamlを入れておくviewsディレクトリ、
ドキュメントルートになるpublicディレクトリをつくります。

$ touch app.rb
$ touch config.ru
$ mkdir views
$ mkdir public

アプリケーションのコードはこんな感じです

$ vim app.rb
require "sinatra/base"
require "sass"
require "haml"
require "coffee-script"

module Portfolio
  class App < Sinatra::Base
    get '/' do
      'hello'
    end
  end
end
$ vim config.ru
require "./app"
run Portfolio::App

でアプリがちゃんと動くかどうか確認してみる
shotgunを入れておいたので

$ bundle exec shotgun
== Shotgun/WEBrick on http://127.0.0.1:9393/
[2012-04-26 23:49:20] INFO  WEBrick 1.3.1
[2012-04-26 23:49:20] INFO  ruby 1.9.2 (2011-07-09) [x86_64-darwin11.2.0]
[2012-04-26 23:49:20] INFO  WEBrick::HTTPServer#start: pid=457 port=9393

localhost:9393にアクセスして hello が表示されればOKです
そしたらこっからガシガシコード書いていくんですが、shotgun使ってるのでapp.rbを編集してもサーバの再起動が必要ありません。
home、about、galleryの3ページと仮定して以下のように書き換えました

$ vim app.rb
module Portfolio
  class App < Sinatra::Base
    before do
      @site_name = 'My Portfolio'
      @nav = ['home', 'about', 'gallery']
    end
    
    get '/' do
      haml :index
    end

    get '/about/?' do
      haml :about
    end

    get '/gallery' do
      haml :gallery
    end
  end
end

before do ... end の中で共通の処理を記述できます。
site_nameとnavを用意しておきました。変数に@をつけておくとインスタンス変数と言ってviewに渡せるようになります。
htmlはhamlで書くので以下のようにします。

$ vim views/index.haml
%h1= @site_name
%nav
  %ul
    - @nav.each do |n|
      %li
        %a{href:"/#{n}"}= n
%p welcome to my portfolio site

でもこれだとheadとかないので layout を作成します

$ vim views/layout.haml
!!! 5
%html
  %head
    %meta{charset:'utf-8'}
      %title= @site_name
  %body
    = yield

yieldの部分に各ページの内容が入ります。
次はsassというかscssを使ってみます。
まずはapp.rbを編集して、

$ vim app.rb
get '/stylesheets/base.css' do
  scss :base
end

galleryの下に追記しておきました。
ここまで出来たら後はviews内にscssファイルを作って作業していくだけです。
簡単ですね!

ちなみにrubyのシンボル(:で始まる文字列)は " で囲めば / とかも使えるので
views内でファイルが平置きになってるのが嫌な人は views/haml や views/scss を作っておいて
app.rbで

haml :"haml/index"

と指定すればちゃんと呼び出せますよ!

sinatraとかhamlとかscssとかcoffeescriptの詳しい使い方はドキュメントを読もー

2012年1月31日火曜日

[ruby]最初に知っておけば良かったbundlerの使い方 rails編

PHPの代わりというか、次のレベルとしてRubyを使うならまず最初にbundlerの使い方を知っておきたかった。 以下自分なりに覚えたbundlerの使い方を記録しておく。

作業ディレクトリを作る。

$ mkdir hoge_project

railsなんかはディレクトリ名がそのままアプリ名になっちゃうから気をつける
(これってオプションでディレクトリ名と別の名前渡せるのかな??)

作業ディレクトリでbundlerのinitを実行する。

$ cd hoge_project
$ bundle init
Writing new Gemfile to /Users/username/hoge_project/Gemfile

これでサンプルのGemfileが作られる。
▼内容

# A sample Gemfile
source "http://rubygems.org"

# gem "rails"

▼一行目を削除し、四行目のコメントアウトを外してバージョンを3.1.3に指定

source "http://rubygems.org"

gem "rails", "3.1.3"

プロジェクトローカルな状態でgemをインストール

$ bundle install --path vendor/bundle

地味にbundlerの便利なところはこの時点でvendorフォルダの有無に関わらずインストール出来ちゃうところ。

Fetching source index for http://rubygems.org/
Installing rake (0.9.2.2) 
Installing multi_json (1.0.4) 
Installing activesupport (3.1.3) 
Installing builder (3.0.0) 
Installing i18n (0.6.0) 
Installing activemodel (3.1.3) 
Installing erubis (2.7.0) 
Installing rack (1.3.6) 
Installing rack-cache (1.1) 
Installing rack-mount (0.8.3) 
Installing rack-test (0.6.1) 
Installing hike (1.2.1) 
Installing tilt (1.3.3) 
Installing sprockets (2.0.3) 
Installing actionpack (3.1.3) 
Installing mime-types (1.17.2) 
Installing polyglot (0.3.3) 
Installing treetop (1.4.10) 
Installing mail (2.3.0) 
Installing actionmailer (3.1.3) 
Installing arel (2.2.1) 
Installing tzinfo (0.3.31) 
Installing activerecord (3.1.3) 
Installing activeresource (3.1.3) 
Using bundler (1.0.21) 
Installing json (1.6.5) with native extensions 
Installing rack-ssl (1.3.2) 
Installing rdoc (3.12) 
Installing thor (0.14.6) 
Installing railties (3.1.3) 
Installing rails (3.1.3) 
Your bundle is complete! It was installed into ./vendor/bundle

こんな感じでインストール完了。
最初はrails以外のgemがわんさかインストールされちゃってる事にかなりびっくりしました。
今なら依存関係があるから当たり前やんって思うけど、この辺のニュアンスってなかなか初心者には分かりづらい。

ここまでだとrailsアプリはまだ出来てないのでスケルトンを作る

$ bundle exec rails new . -T -d mysql

このコマンドの意味するところは
プロジェクトローカルのgemを使い、
railsの新しいアプリケーションをこのディレクトリで作成し、
かつtestディレクトリを省略し、
DBはmysqlを選択
ということです。

▼で実行するとこんな問いかけをくらう

       exist  
      create  README
      create  Rakefile
      create  config.ru
      create  .gitignore
    conflict  Gemfile
Overwrite /Users/username/hoge_project/Gemfile? (enter "h" for help) [Ynaqdh] 

既存のGemfileをrails仕様に上書きしてもいいか?ということで問題ないので enter

       force  Gemfile
      create  app
      create  app/assets/images/rails.png

          ... 省略 ...

         run  bundle install

でここでエラーが発生するんですよねぇ…
/Users/username/.rvm/gems/ruby-1.9.2-p290@global/gems/bundler-1.0.21/lib/bundler/resolver.rb:280:in `resolve': Could not find gem 'jquery-rails (>= 0) ruby' in any of the gem sources listed in your Gemfile. (Bundler::GemNotFound)

でも気にせずrspecをGemfileに追加

group :development, :test do
  gem 'rspec-rails'
end

でbundle installに再チャレンジ

$ bundle install
Fetching source index for http://rubygems.org/
Installing coffee-script-source (1.2.0) 
Installing execjs (1.3.0) 
Installing coffee-script (2.2.0) 
Installing coffee-rails (3.1.1) 
Installing diff-lcs (1.1.3) 
Installing jquery-rails (1.0.19) 
Installing mysql2 (0.3.11) with native extensions 
Installing rspec-core (2.8.0) 
Installing rspec-expectations (2.8.0) 
Installing rspec-mocks (2.8.0) 
Installing rspec (2.8.0) 
Installing rspec-rails (2.8.1) 
Installing sass (3.1.12) 
Installing sass-rails (3.1.5) 
Installing uglifier (1.2.3) 
Your bundle is complete! It was installed into ./vendor/bundle
※既にインストール済みの行は省きました

よし!
これでrailsアプリのスケルトン出来ました。
後はrailsコマンドとかrakeするときに常に bundle exec を付けておけば
プロジェクトローカルのgemで実行されます。

アプリケーション毎のbundlerの設定は bundle config で確認できる(.bundle/configファイルの中身を見てる)

$ bundle config
Settings are listed in order of priority. The top value will be used.

path
  Set for your local app (/Users/username/hoge_project/.bundle/config): "vendor/bundle"

disable_shared_gems
  Set for your local app (/Users/username/hoge_project/.bundle/config): "1"

開発用サーバを起動

$ bundle exec rails s
=> Booting WEBrick
=> Rails 3.1.3 application starting in development on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
[2012-01-31 17:06:22] INFO  WEBrick 1.3.1
[2012-01-31 17:06:22] INFO  ruby 1.9.2 (2011-07-09) [x86_64-darwin10.8.0]
[2012-01-31 17:06:22] INFO  WEBrick::HTTPServer#start: pid=1895 port=3000

ちなみにこの時に -p (ポートオプション)を付ければ好きなポート番号でWEBrickを起動できますね

まだ初心者が知っておいたほうがいい事があって、
バージョン管理している場合気を付けなくちゃいけないのは vendor/bundle ディレクトリは管理の対象にしないこと。
これって本業のプログラマーさんなら当たり前なんだろうけど。
mysql2とか、環境に依存するgemもあるから環境毎にbundle installするべきだってことに気づくのが大分遅かった…

2012年1月6日金曜日

Nokogiriでページタイトルを取得する

これがあんまりうまく行かない場合が多い。ローカル(Mac)では取得できるけどherokuでダメってことも多い。
ということで今のところ以下のように落ち着いてる。 取得先のHTML構造が壊れていたり、URLに日本語がそのまま含まれていたりすると厄介。
2011年12月6日火曜日

ActiveAdminをhttpsで使う

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

2011年12月5日月曜日

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

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