すがブロ

sugamasaoのhatenablogだよ

Rails 4.1のenumの挙動

みんな大好きenum

DBのカラムでステータスとか使うとき、ぼくは数値派なんですけど、enumで掛けたら楽で良いですよねみたいのあります。ありますよね。

で、Rails 4.1ではそういうのが導入されたっぽいので試してみました。

rails 4.1をインストールしてプロジェクト作ったりする

$ gem install rails --pre --no-ri --no-rdoc
$ rails new sample
$ cd sample
$ ./bin/rails g scaffold product name:string status:integer
$ ./bin/rake db:migrate

rails cでフツーに登録してみる(ここは何の変哲も無い)。

irb(main):005:0> Product.create!(name: "hoge", status: 99)
   (0.1ms)  begin transaction
  SQL (0.2ms)  INSERT INTO "products" ("created_at", "name", "status", "updated_at") VALUES (?, ?, ?, ?)  [["created_at", "2014-03-26 01:25:21.026233"], ["name", "hoge"], ["status", 99], ["updated_at", "2014-03-26 01:25:21.026233"]]
   (1.9ms)  commit transaction
=> #<Product id: 2, name: "hoge", status: 99, created_at: "2014-03-26 01:25:21", updated_at: "2014-03-26 01:25:21">

statusの値が99でも保存できちゃう。そのままでも良いんだけど、validatesのおさらいとして例えば0〜2までに制限してみようか。

class Product < ActiveRecord::Base
  validates :status, inclusion: {in: 0..2}
end

ためしてみよう

Loading development environment (Rails 4.1.0.rc2)
irb(main):001:0> Product.create!(name: "hoge", status: 99)
   (0.1ms)  begin transaction
   (0.1ms)  rollback transaction
ActiveRecord::RecordInvalid: Validation failed: Status is not included in the list
irb(main):003:0* Product.create!(name: "hoge", status: 2)
   (0.1ms)  begin transaction
  SQL (0.4ms)  INSERT INTO "products" ("created_at", "name", "status", "updated_at") VALUES (?, ?, ?, ?)  [["created_at", "2014-03-26 01:27:51.238248"], ["name", "hoge"], ["status", 2], ["updated_at", "2014-03-26 01:27:51.238248"]]
   (1.6ms)  commit transaction
=> #<Product id: 3, name: "hoge", status: 2, created_at: "2014-03-26 01:27:51", updated_at: "2014-03-26 01:27:51">

数値の範囲指定ができましたね。

それではenumを使ってみよう

enumの設定をしてみよう。ややこしくなるので、validatesは消します。ついでに書いておくと、enumの項目自体はテキトウなのでスルー推奨です。

class Product < ActiveRecord::Base
  enum status: {
    normal: 0, # 通常
    sale: 1,   # 特売
    empty: 2,  # 在庫切れ
  }
end

これで試してみよう。まずは正常系で。

irb(main):005:0* Product.create!(name: "hoge", status: 2)
   (0.1ms)  begin transaction
  SQL (0.2ms)  INSERT INTO "products" ("created_at", "name", "status", "updated_at") VALUES (?, ?, ?, ?)  [["created_at", "2014-03-26 01:33:06.501462"], ["name", "hoge"], ["status", 2], ["updated_at", "2014-03-26 01:33:06.501462"]]
   (1.6ms)  commit transaction
=> #<Product id: 6, name: "hoge", status: 2, created_at: "2014-03-26 01:33:06", updated_at: "2014-03-26 01:33:06">
irb(main):006:0> Product.create!(name: "hoge", status: :sale)
   (0.1ms)  begin transaction
  SQL (0.6ms)  INSERT INTO "products" ("created_at", "name", "status", "updated_at") VALUES (?, ?, ?, ?)  [["created_at", "2014-03-26 01:33:13.877152"], ["name", "hoge"], ["status", 1], ["updated_at", "2014-03-26 01:33:13.877152"]]
   (1.5ms)  commit transaction
=> #<Product id: 7, name: "hoge", status: 1, created_at: "2014-03-26 01:33:13", updated_at: "2014-03-26 01:33:13">
irb(main):005:0> Product.create!(name: "hoge", status: 'sale')
   (0.1ms)  begin transaction
  SQL (0.6ms)  INSERT INTO "products" ("created_at", "name", "status", "updated_at") VALUES (?, ?, ?, ?)  [["created_at", "2014-03-26 01:57:26.957196"], ["name", "hoge"], ["status", 1], ["updated_at", "2014-03-26 01:57:26.957196"]]
   (1.4ms)  commit transaction
=> #<Product id: 15, name: "hoge", status: 1, created_at: "2014-03-26 01:57:26", updated_at: "2014-03-26 01:57:26">

このように、シンボルや文字列、そして数値でも保存してくれるようになった。便利。

では範囲外の値を入力すると?

irb(main):007:0> Product.create!(name: "hoge", status: 99)
ArgumentError: '99' is not a valid status
irb(main):009:0* Product.create!(name: "hoge", status: :hoge)
ArgumentError: 'hoge' is not a valid status
irb(main):011:0* Product.create!(name: "hoge", status: 'hogehoge')
ArgumentError: 'hogehoge' is not a valid status

ことごとくArgumentErrorとなる。create!で試しているけど、createnewでも試してみよう。

irb(main):007:0> Product.create(name: "hoge", status: 99)
ArgumentError: '99' is not a valid status
irb(main):009:0* Product.new(name: "hoge", status: 99)
ArgumentError: '99' is not a valid status

create!だけに限らず、newメソッドとかでも引数に異なる範囲の値が入るとArgumentErrorになる。 普通のvalidatesに条件を書く場合は ActiveRecord::RecordInvalid: Validation failed: Status is not included in the list みたいにActiveRecord::RecordInvalidの例外クラスが送出されるけど、そうではない(例外クラス的にも、発生タイミング的にも)ので気をつけた方が良さそう。

validatesではないから挙動が異なるのは当然といえば当然だけど、使い勝手としては同じような挙動のほうが嬉しかったんだけどそうではなかったという備忘録エントリーです。

Rails詳しくないのでよくわかりませんが、ここら辺、正式リリースまでに挙動が変わったりするかしら?

書かなくてはならない事柄(追記)

こちらも何卒よろしくお願い致します。

Webアプリエンジニア養成読本[しくみ、開発、環境構築・運用…全体像を最新知識で最初から! ] (Software Design plus)

Webアプリエンジニア養成読本[しくみ、開発、環境構築・運用…全体像を最新知識で最初から! ] (Software Design plus)

SQLite3の実際の型

SQLiteの型のなぞ

SQLite3の型はスゲーざっくりしていると聞いていたのだけど、RailsでデータベースをSQLiteにして、適当なテーブルを作成したら、なんか varchar とか出てくる。どういうことなんだってばよ? というのを調査してみた。

まずはRailsでテーブルを作るところまで

結論から言うと、別にRailsを使う必要は無いんだけども、まぁせっかくなんでね。

ちなみに、-T は unit/test のテンプレートを作らないというオプションで、単なる手クセなので気にしないで(普段はrspecを使うので)。

% rails new sample -d sqlite3 -T 
(snip)
cd sample
% rails g scaffold blog title:string body:text like:integer
% bundle  exec rake db:migrate

ちなみに、ここの例ではテキトーなブログシステムを作る、みたいのを想定してもらいたい。likeはそのブログに対するいいね数みたいなものだと思って。

データの確認

まず、念のためRails側のmigrateでどんな型が指定されているかを確認する。

% cat db/migrate/20111113064850_create_blogs.rb
class CreateBlogs < ActiveRecord::Migration
  def change
    create_table :blogs do |t|
      t.string :title
      t.text :body
      t.integer :like

      t.timestamps
    end
  end
end

あたりまえだけど、指定した通りである。
さて、SQLiteでDBを開いてみよう(rails db とかでも大丈夫だと思うけど)。

% sqlite3  db/development.sqlite3 

では、さっきのテーブルの中身を見てみよう。

sqlite> .dump blogs
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE "blogs" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar(255), "body" text, "like" integer, "created_at" datetime, "updated_at" datetime);
COMMIT;

整形してなくてアレだけど、varchar や datetime とかが指定されてる。無いんじゃないの。

ここからが本題

こういう時は公式のドキュメントにあたるのが一番ですね。

で、ここをきちんと読んでみると、1.0 Storage Classes and Datatypes に、データ型として5つあるよと書いてある(このデータ型はカラムの型ではなく、実データを扱う際の型らしい?)。

  • NULL
  • INTEGER
  • REAL
  • TEXT
  • BLOB

さらに、1.2 では Date型を保持する型としては TEXT の場合と REAL の場合と INTEGER の場合があるとか書いてある。

カラムの型は

2.0 Type Affinity に書いてある。SQLite3ではこの5つが定義されているようだ。

  • TEXT
  • NUMERIC
  • INTEGER
  • REAL
  • NONE

つまり、SQLiteの実際のカラムの型っていうのは、ここの事らしい。で、更にその下 2.2 Affinity Name Examples に他のSQLとの互換のためにどのような型指定の場合はどの型に変換されるかのテーブルがある。

というわけで

今回の場合だと以下のような型に変換されているような気がする。

  • title => TEXT
  • body => TEXT
  • like => INTEGER
  • created_at => NUMERIC
  • updated_at => NUMERIC

なんとなくわかったのだけど、その変換された型を実際に確認する場合ってどうすれば良いんですかね。。。

ActiveRecord と実際のDBの型の対応を確認する

rails console で確認できる

環境
確認方法
ActiveRecord::Base.connection.native_database_types

でアクセスすると確認できる。

実際にやってみる

rails console して、上記で書いたプロパティを確認する。

ruby-1.9.2-head > pp ActiveRecord::Base.connection.native_database_types
{
:primary_key=>"int(11) DEFAULT NULL auto_increment PRIMARY KEY", 
:string=>{:name=>"varchar", :limit=>255}, 
:text=>{:name=>"text"}, 
:integer=>{:name=>"int", :limit=>4}, 
:float=>{:name=>"float"}, 
:decimal=>{:name=>"decimal"}, 
:datetime=>{:name=>"datetime"}, 
:timestamp=>{:name=>"datetime"},
:time=>{:name=>"time"}, 
:date=>{:name=>"date"},
:binary=>{:name=>"blob"}, 
:boolean=>{:name=>"tinyint", :limit=>1}
}

こんな感じになる。

Rails3で困っちゃった事リスト

Rails2.x 系の情報だと動かない!!!

Rackアプリケーションになったことやモジュール化を進めた影響だと思うのだけど、Rails2.x系ではうまく行くと書いてあるやり方が Rails3 になってうまくいかなかったりしたので、実際にハマった事をメモしておくよ。
ちなみに、環境は以下の通り

  • Rails 3.0.1
  • Ruby 1.9.2
  • そもそも Rails自体よくわかってない(!)

以下はあくまでも自分自身のログなので、Rails3……というか Rails の作法としてはこうするんだよ、というベストアンサーがあったらぜひ教えてほしいです。

Session をブラウザが終了しても終わらないようにしたい

ログインした後のいわゆる Session の有効期限を変更したい

今までなら

に書いてあるように

ActionController::Base.session_options[:session_expires] = 1.months.from_now

こんな感じで更新できた。
が、Rails3 では ActionController::Base に session_options なんてネーよと言われる。

対応
request.session_options[:expire_after] = 1.months.from_now

このように、 request オブジェクトに設定させる。
アクセス毎に request.session_options.inspect してもなぜか :expire_after は nil になってしまっていて果たしてこれが全うな設定方法なのかは疑問。……たまたま別の要因でうまく行ってるだけかもしれないけれど。

Production モードで動かしたら画像ファイルが見れなくなった

Production モードで send_file で表示してる画像が0byteで見れない

いきなり見れなくなる(エラーとかでない)のでビビった。 public ディレクトリが見れなくなるのとは別の問題で、どうやら Rails3 での不具合?らしい。
この Rails プロジェクトを作ったときは Rails3 RC だったので、解消されているかもしれない。

このような状態になる。

対応

上記のサイトにある通り、 config/environments/production.rb にある

config.action_dispatch.x_sendfile_header = "X-Sendfile"

をコメントアウトにして事なきをえた。
深追いしていないからわからないけれど

にあるようにX-Sendfileに Apache が対応していないからなのかもしれない*1

routes.rb でネストした URL を作りたい

管理者画面を作るときとか

テーブル構成はネストしていない状態で、 controller だけネストさせたい。
例えば、以下のようなURLでhogeテーブルに対する CRUD 操作をしたいとか。
/admin/hoge

対応

routes.rb には以下のように設定する

scope :module => 'admin' do
  match 'admin/hoge' => 'hoge#show'
end

controller はディレクトリ構成とモジュール構成に注意する
app/controllers/admin/hoges_controller.rb

class Admin::HogesController < ApplicationController
(...)
end

view は model_path メソッドを変更する必要がある。
model_path にすると、 /admin にネストしないので、 admin_model_path のようにする必要がある。

Rails.root/lib が読み込まれない

Rails3 から読み込まれなくなったらしい

過去の事をしらないので良くわかってないが、こんな風にすると良いらしい
config/application.rb

    # RAILS_ROOT/lib/hoge_dir/fuga.rb があるような場合を想定
    config.autoload_paths += %W(#{config.root}/lib/hoge_dir)

log ファイルのパスはドコ

Rails が現在使っている log ファイルのパスを知りたい

決め打ちじゃなくて、logger が使ってるパスを知りたい場合。以下のサイトが参考になった。

対応

log.paths ってことは複数存在することを前提にしているようだけど、用途は良くわかってない。少なくとも、狙いのファイルは先頭にあるので*2、以下で取れる。

Rails.configuration.paths.log.paths.first

log ファイルのローテーションしたい

log ファイルを適宜変更させる

ここだと config/environment.rb に書けとあるけど、 Rails3 だと有効ではないっぽい。

対応

しかたないので config/environments/*.rb にそれぞれ記述することにした。
記述内容自体は上記のサイト同様、以下のように書けば良い*3

  config.logger = Logger.new(Rails.configuration.paths.log.paths.first, 'daily')
追記1

id:pinzolo さんにコメント頂きました。
application.rb に書くと良いらしいです。

> ここだと config/environment.rb に書けとあるけど、 Rails3 だと有効ではないっぽい。
以前の config/environment.rb の内容は config/application.rb に変更されてますので、config/application.rb に書けば全環境で読み込んでくれますよ。

追記2

記述する場所云々の話以前に、そもそも Logger クラスを使う*4のは悪手っぽい。例えば log レベルを Rails がよしなに変えてくれてる部分とか config/initializers/ で指定しているログフォーマットとかがぶっ飛ぶ。
おとなしく logrotated でやれってことですかね。

メールの受信(パース)

メールを Rails アプリ側で取り込む場合

ここの「メールの受信」を ISO2022-JP な Subject のメールを食わせるとエンコーディングの不一致で死ぬ*5
正確には Mail クラスのフィールドの取扱い方がまずいようだ。

しょうがないのでモンキーパッチを当てた


ただ、これだと元々の Mail ライブラリのテストで何件か fail してしまうので、良い直しでは無い。本当に、その場しのぎである。
また、この対応でサブジェクトは対応できるが、添付ファイル名のエンコーディングにはうまく対応できていないので、そちらはそちらで別途対応を考える必要がある。
今回は妥協できる範囲だったので、上記の対応で辞めてしまったのですが、これ、みんな困ってないのかしら???

*1:有効にする、というような設定はしていないので

*2:1ファイルしか無いけど

*3:パスの取得方法上記のURLからは変更している

*4:というか new して上書きしてる

*5:Subject が UTF-8 の場合は、デフォルトエンコーディングがUTF-8だと偶然によってちゃんと動く。本当は複数行の Subject フィールドを連結する際に一つのエンコーディングに統一する必要がある

モデルにメソッドを持たせる

こんな感じの投稿システムがあったとします

sqlite> .tables
comments posts

む、sqlite3には mysql とかの describe 相当のコマンドが無いのだろうか。
とりあえずデータを突っ込んだ select で勘弁してね。

id|title|body|created_at|updated_at
1|title1|body|2010-09-25 05:55:18.912592|2010-09-25 05:55:18.912592
2|title2|body|2010-09-25 05:55:31.281979|2010-09-25 05:55:31.281979

いわゆるブログのエントリ的なものを想定して、titleとbodyっていうカラムがある。
そして、その各エントリにcommentが付く。

id|post_id|name|body|created_at|updated_at
1|1|hogehoge|comment1|2010-09-25 05:57:32.057127|2010-09-25 05:57:32.057127
2|1|hogehoge|comment2|2010-09-25 05:57:39.476946|2010-09-25 05:57:39.476946
3|1|hogehoge|comment3|2010-09-25 05:57:42.828758|2010-09-25 05:57:42.828758
4|2|unko|comment1|2010-09-25 05:57:53.740980|2010-09-25 05:57:53.740980
5|2|hogehoge|comment2|2010-09-25 05:58:03.020882|2010-09-25 05:58:03.020882

コメントには、対象となる post_id をもって紐付けさせる。

モデルでの関連付け

vim app/models/post.rb

has_manyを付ける

class Post < ActiveRecord::Base
  has_many :comments
end

rails console で以下のように試すと、コメントデータも取れる。

Post.find(1).comments
=> [#, #, #]

投稿メッセージにコメント数をつけたい

いわゆる commnet(1) とかをつけたい場合ね。
上記が試せていれば、

Post.find(1).comments.length

とかで取れる訳だけど、json などで渡すときに不都合ですよね。

まず、モデルにメソッドを定義する

一応、何回も呼ばれたときの為にキャッシュしておく。

class Post < ActiveRecord::Base
  has_many :comments

  def comment_count
    @comment_count ||= comments.length
  end
end

rails console で確認してみよう。

ruby-1.9.2-head > Post.find(1).comment_count
=> 3

おお、できてる。

to_json(to_xml)でメソッド呼び出しをする

:methods オプションで呼べる。

ruby-1.9.2-head > puts post.to_json(:methods => :comment_count)
{"post":{"body":"body","created_at":"2010-09-25T05:55:18Z","id":1,"title":"title1","updated_at":"2010-09-25T05:55:18Z","comment_count":3}}

整形するとこんな感じで、最後に comment_count っていうのが付く

{
    post: {
        body: body (string)
        ,created_at: 2010-09-25T05:55:18Z (string)
        ,id: 1 (number)
        ,title: title1 (string)
        ,updated_at: 2010-09-25T05:55:18Z (string)
        ,comment_count: 3 (number)
    }
}

整形は例のごとく JSON整形 を使った。
ちなみに、:methods で複数のメソッドを呼びたい場合は [:method名, :method名]のような感じで配列にすると良い。

これで

データを弄り回さずに出力用の形式に整形できますね。
enjoy!

Rails のモデル関係と to_json(to_xml)

関係を持ったテーブルと出力方法について

Rails初心者にありがちなメモをするよ。
ちなみに、環境は Ruby1.9.2 と Rails3 です。

テーブル間のリレーションについて

ユーザ情報テーブルと、ユーザが持ってる所持品のテーブル的なものがあるとして。
面倒なのでスゲー適当だけど以下のような定義で作った。

rails g scaffold user name:string item_id:integer
rails g scaffold item name:string

item_id は items テーブルの id が入るってことね。

  • users
  • items
    • name:string

これで、ユーザはitem_idに items テーブルのidを一つもつ感じ。

model に関連をつける

いわゆる has_many とか has_one とか belongs_to のアレ。
今回の件だとこんな感じ*1

vim app/models/user.rb

class User < ActiveRecord::Base
  belongs_to :item
end

これでおk。
こうすることで、user.item で item_id に紐づいた値を探してくれるようになる。

これを json にして出力したいぜ

例えば以下のようなデータがあるとして

  • users
    • id => 1
    • name => aaaa
    • item_id => 1
  • items
    • id => 1
    • name => item1

irbで確認するとこんな感じ。

ruby-1.9.2-head > User.find_by_id(1)
=> #
ruby-1.9.2-head > User.find_by_id(1).item
=> #

うん、予定通りのデータが入ってるね。じゃあ、これを json で出力してみましょう。

ruby-1.9.2-head > User.find_by_id(1).to_json

{
    user: {
        created_at: 2010-09-13T21:18:44Z (string)
        ,id: 1 (number)
        ,item_id: 1 (number)
        ,name: aaaa (string)
        ,updated_at: 2010-09-13T21:18:44Z (string)
    }
}

たしかに json 形式なんだけど、item の値が入っていない。あんまりだ。
ちなみに、json の整形は JSON整形 を使った。

to_json にはオプションがいろいろある

テストデータがアレな気がするけど、オプションについて詳しく載っていてとても良い。

つまり :include しろってことだってばよ

ruby-1.9.2-head > puts User.find_by_id(1).to_json(:include => :item)

{
    user: {
        created_at: 2010-09-13T21:18:44Z (string)
        ,id: 1 (number)
        ,item_id: 1 (number)
        ,name: aaaa (string)
        ,updated_at: 2010-09-13T21:18:44Z (string)
        ,item: {
            created_at: 2010-09-13T21:17:10Z (string)
            ,id: 1 (number)
            ,name: item1 (string)
            ,updated_at: 2010-09-13T21:17:10Z (string)
        }
    }
}

やった、itemのデータも引っ張ってこれた!
ただ、これを出力データとするにはちょっと冗長すぎる。updated_at とか必要かっつーと入らなかったりする。

:only や :except で出力を制限できる

例えばこんな感じだ

User.find(:all)[0].to_json({:include => {:item => {:only => [:id,:name]}}, :only => [:name]})

{
    user: {
        name: aaaa (string)
        ,item: {
            id: 1 (number)
            ,name: item1 (string)
        }
    }
}

これ、only が items にも users にも指定してあって、ちょっと重複した感じがしてイヤなのだけど、上位(この場合 users)で指定した場合、その値が子の要素にも only の設定が伝播してしまう。
今回の場合、両方とも name しかないからあまり実害はないけれど、実際の場合はそんな訳はないので、個別に出力する属性を指定する感じの方が良いと思う。
ちなみに、to_xml でも同様です。

じゃあ、respond_with の場合ってどうなるのよ

こんな感じで実装できた。

class UsersController < ApplicationController

    respond_to :html, :xml, :json

  # GET /users
  # GET /users.xml
  def index
    @users = User.all
    respond_with(@users, {:include => {:item => {:only => [:id,:name]}}, :only => [:name]})
  end
  (略)
end

従来の respond_to の場合はこんな感じだろうか(面倒なので、とりあえず json の場合のみ)。

    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @users }
      format.json  { render :js => @users.to_json({:include => {:item => {:only => [:id,:name]}}, :only => [:name]}) }
    end

こう見ると respond_with の cool 感が際立ってやべぇすな。

*1:意味的にあったるかは微妙な気がする。itemの所属するって変じゃね!?

Railsで定数を別ファイルで管理したい? よろしい、ならば Settingslogic だ。

ソースの中で定数として扱うのではなく、設定ファイル的に扱いたい

Rubyはそれなりに長い間使っていますが、Railsはメジャーバージョン毎にちょっと触るくらいで、まったくベストプラクティスとか知らないんですね。
で、いまは作る際のお手本として 日本Ruby会議 2010, 8月27日〜29日 のソースである ruby-no-kai/rubykaigi · GitHub を見てパクれそうなのはパクるというスタンスでやってます。

で、本題の設定ファイルの扱いについて

上記 rubykaigi の Gemfile を見ると 'configatron' っていうのがある。
なので、これが cool な設定ファイルを扱うライブラリなのかしら、と思ってたのですが、ちょうど id:ursm さんから

という助言を頂いたので、そっちで試してみることにしました。

Settingslogicの使い方

binarylogic/settingslogic · GitHub の README にある通りですが……

  • Gemfile に 'settingslogic' を追加
  • bundle update でインストール
設定ファイル用 model を作る

vim app/models/settings.rb

class Settings < Settingslogic
  source "#{Rails.root}/config/application.yml"
  namespace Rails.env
end

ただ、グローバルな設定をしたいなら namepsace は無くても良い(詳しくは後述)。

設定ファイルを作成する

上記の source で指定しているパスと合わせる必要があるので注意。

vim config/application.yml

# app/config/application.yml
defaults: &defaults
  cool:
    saweet: nested settings
  neat_setting: 24
  awesome_setting: <%= "Did you know 5 + 5 = #{5 + 5}?" %>

development:
  <<: *defaults
  neat_setting: 800

test:
  <<: *defaults

production:
  <<: *defaults

こうすることで、 Rails環境変数によって defaults + test などを変化させることができるので、環境によって値を変えたい場合でも特に余計な手順を踏むことなく、柔軟に対応できる。
また、 namespace で値を変える必要ないから不要だよ、という場合は namespace をコメントアウトして、 application.yml のほうで defaults などを記載せず直接 yml で値を書いてしまえば使える(逆に言えば、namespace を指定する場合は、対応する namespace の定義が無いと何も読み込んでくれない)。

読み出し方

app/controllers/hoge_controller.rb 内から普通に読み出すことができる。

logger.debug Settings.cool.saweet
#=> nested settings

Settingslogic 気に入った

model を挟むというのがユニークですけど、yml で書いたのが特に意識せずそのまま使えてラクで良いですね。これは良い!
enjoy!