* Railsメモ [#ubc1fca1]

#setlinebreak(on);

- 関連
-- [[Ruby on Rails]]
-- [[Railsでユニットテストを行う]]
-- [[RailsでMongoDBを使用する]]
-- [[RailsでMongoDBを使用する為の環境設定メモ(Windows)]]
-- [[Railsのmongoidでユーザ認証]]
-- [[RailsでMondoid使用時のユニットテスト]]
-- [[ApacheとRailsをmod_proxyで連携する]]
-- [[Railsをthinで複数起動してApacheでロードバランス]]
-- [[websocket-railsインストール]]

#contents

** 独自定数を定義する [#f83f5d45]
#html(<div style="padding-left:20px;">)
発環境ごとに定数を管理できるconfig(旧:rails_config )を利用する。

Gemfileに追記
#mycode2(){{
gem 'config'
}}

インストール
#mycode2(){{
bundle install --path vendor/bundle
bundle exec rails g config:install
}}

定数の記述例) config/settings/development.yml
#mycode2(){{
test:
  val1: "TEST_VAL1"
}}

利用例)
#mycode2(){{
Settings.test[:val1]
}}

#html(</div>)

&br;

** 数値編集 [#bf1d322c]
#html(<div style="padding-left:20px;">)

*** カンマ編集 [#he280aab]
#mycode2(){{
<%= number_with_delimiter(123456789) %>   # => 123,456,789
}}

*** 表示桁数の指定 [#x6da8df4]
#mycode2(){{
<%= number_with_precision( 12.345, precision: 2 ) %> #=> 12.35
}}

*** 通貨 [#pb9a09bc]
#mycode2(){{
<%= number_to_currency( 1234.5 ) %>    # => 1,235円 ※ロケール:ja の場合
}}
※ config/locales/ja.yml を編集する事で &yen;1,235 のように表示する事も可能。
 (number -> currency -> format 配下の format と unit )


#html(</div>)

&br;

** テキスト編集 [#y4ae9c3d]
#html(<div style="padding-left:20px;">)

*** 文字列の切り捨て [#ze9eee59]
#html(<div style="padding-left:10px;">)

#myhtml2(){{
<%= truncate("桁数や文言を指定して切り捨てます。オプションには : length、: separator、: omission が指定できます。", :length => 10) %>
<!-- 結果:「桁数や文言を指...」-->

<%= truncate("桁数や文言を指定して切り捨てます。オプションには : length、: separator、: omission が指定できます。", :length => 50, :separator => "。") %>
<!-- 結果:「桁数や文言を指定して切り捨てます...」-->
}}

オプション
|オプション|説明|h
|:length|切り捨てる桁数。(デフォルト:30)|
|:separator|切り捨てる箇所を表す文字列|
|:omission|切り捨て時に末尾に付与する文字列(デフォルト:...)|

#html(</div>)

*** ハイライト表示 [#c7d5905b]
#html(<div style="padding-left:10px;">)
#myhtml2(){{
<%= highlight('このヘルパー(highlight)は指定文字列をハイライト表示します', "highlight") %>
<!-- 結果:「このヘルパー(<mark>highlight</mark>)は指定文字列をハイライト表示します」-->

<%= highlight('このヘルパー(highlight)は指定文字列をハイライト表示します', "highlight", :highlighter => '<span style="color:#f00;">\1</span>') %>
<!-- 結果:「このヘルパー(<span style="color:#f00;">highlight</span>)は指定文字列をハイライト表示します」-->
}}
#html(</div>)


*** HTMLエスケープを抑制する [#l1e8777d]
#html(<div style="padding-left:10px;">)
#mycode2(){{
<%= "&lt;a href='#test'&gt;test link&lt;/a&gt;" %>                       <!-- 結果:&amp;lt;a href='#test'&amp;gt;test link&amp;lt;/a&amp;gt;   -->
<%= raw("&lt;a href='#test'&gt;test link&lt;/a&gt;") %>               <!-- 結果:&lt;a href='#test'&gt;test link&lt;/a&gt;  -->
<%= "&lt;a href='#test'&gt;test link&lt;/a&gt;".to_s.html_safe %>       <!-- 結果:&lt;a href='#test'&gt;test link&lt;/a&gt;  -->
}}
※ html_safe は nil の場合にエラーになるので、必ず to_s してから html_safe する方が良い。
#html(</div>)

#html(</div>)

&br;

** メッセージの国際化対応 [#pe301ed1]
#html(<div style="padding-left:20px;">)
*** config/application.rb を編集 [#bc725e50]
#mycode2(){{
config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}').to_s]     # config/locales 配下のファイルを全て読み込む
config.i18n.default_locale = :ja
}}

*** config/locales 配下に定義ファイルを作成する [#mb3b0f8b]
例)
#html(<div style="border:1px solid #000;display:inline-block;padding:10px 20px 10px 20px;line-height:1.5;">)
#html(<span class="fa fa-folder-open"></span> config<br />)
#html(  <span class="fa fa-folder-open"></span> locales<br />)
#html(    <span class="fa fa-file-text-o"></span> en.yml<br />)
#html(    <span class="fa fa-file-text-o"></span> ja.yml<br />)
#html(    <span class="fa fa-folder-open"></span> messages<br />)
#html(       <span class="fa fa-file-text-o"></span> en.yml<br />)
#html(       <span class="fa fa-file-text-o"></span> ja.yml<br />)
#html(</div>)

*** 正しく定義されているか確認 [#r4e7d2e3]
#myterm2(){{
rails console
> YAML.load_file(Rails.root.join("config/locales/ja.yml"))
}}


#html(</div>)

&br;

** バリデータのメッセージを国際化対応する [#t1dc4782]
#html(<div style="padding-left:20px;">)

application.rb を編集([[application.rbの編集>#bc725e50]])したうえで、以下を実施。

*** 対象の言語のメッセージ定義ファイルを取得する [#vf54b7b6]
https://github.com/svenfuchs/rails-i18n/tree/master/rails/locale

*** 元(英語)の定義ファイルの内容が漏れ無く定義されているか確認 ※念のため [#f5499787]
https://github.com/rails/rails/blob/master/activemodel/lib/active_model/locale/en.yml
https://github.com/rails/rails/blob/master/activesupport/lib/active_support/locale/en.yml

*** 取得したファイルを config/locales 配下に置く [#xf19fdf6]
#html(<div style="border:1px solid #000;display:inline-block;padding:10px 20px 10px 20px;line-height:1.5;">)
#html(<span class="fa fa-folder-open"></span> config<br />)
#html(  <span class="fa fa-folder-open"></span> locales<br />)
#html(    <span class="fa fa-file-text-o"></span> en.yml<br />)
#html(    <span class="fa fa-file-text-o"></span><span style="color:#f00;font-weight:bold;"> ja.yml</span><br />)
#html(</div>)

#html(</div>)

&br;

** モデルの項目の日本語名を定義する [#geea34ae]

application.rb を編集([[application.rbの編集>#bc725e50]])したうえで、以下を実施。

#html(<div style="padding-left:20px;">)
例) config/locales/models/モデル名/ja.yml
#mycode2(){{
ja:
  listing_book: "本の一覧"
  editing_book: "本の編集"
  activerecord:
  #mongoid:                  # mongoid を使用している場合
    models:
      book: "本"
    attributes:
      book:
        isbn: "ISBN"
        title: "タイトル"
        price: "値段"
}}
#html(</div>)

#html(<div style="padding-left:20px;">)

例) view/モデル名/index.html.erb
#mycode2(){{
<h1><%= t(:listing_book) %></h1>


<table>
  <thead>
    <tr>
      <th><%= Book.human_attribute_name(:isbn) %></th>
      <th><%= Book.human_attribute_name(:title) %></th>
      <th><%= Book.human_attribute_name(:price) %></th>
      <th colspan="3"></th>
    </tr>
  </thead>


}}

例) view/モデル名/edit.html.erb
#mycode2(){{
<h1><%= t(:editing_book) %></h1>

<%= render 'form' %>

<%= link_to 'Show', @book %> |
<%= link_to 'Back', books_path %>
}}
#html(</div>)

&br;


** ロケールを動的に切り替える(コントローラ等で) [#ef2ba0ad]
#html(<div style="padding-left:10px;">)
#myterm2(){{
I18n.locale = :ja
}}
#html(</div>)

&br;

** コントローラでチェック処理を行う [#p580b033]
#html(<div style="padding-left:20px;">)

#mycode2(){{
flash[:alert] = "XXしてください"
redirect_to :back
return
}}
または
#mycode2(){{
redirect_to :back, alert: 'XXしてください'
return
}}

#html(</div>)

&br;

** モデルのバリデーション定義 [#g35187aa]
#html(<div style="padding-left:20px;">)

*** 必須入力チェック(presence) [#q8bf1b3f]
#mycode2(){{
validates :name, :email, presence: true
}}

*** 空値チェック(absence) [#n19a3989]
#mycode2(){{
validates :login, absence: true
}}

*** 数値チェック(numericality) [#kb7e3a87]
#mycode2(){{
validates :price, numericality: true
validates :price, numericality: { only_integer: true }   # 整数のみの場合
}}
※ greater_than、greater_than_or_equal_to、equal_to、less_than、less_than_or_equal_to 等のオプションも使用可能。
※ message にはプレースホルダとして %{count} が使用可能。

*** 正規表現チェック(format) [#z5647a33]
#mycode2(){{
validates :legacy_code, format: { with: /\A[a-zA-Z]+\z/,  message: "英文字で入力して下さい" }
}}

*** 長さチェック(length) [#zaebe04d]
#mycode2(){{
validates :name, length: { minimum: 2 }
validates :bio, length: { maximum: 500 }
validates :password, length: { in: 6..20 }
validates :registration_number, length: { is: 6 }
validates :bio, length: { maximum: 1000,  too_long: "最大%{count}文字まで使用できます" }
}}
※エラーメッセージは :wrong_length、:too_long、:too_short オプションを指定してカスタマイズ可能。

*** 含有チェック(inclusion) [#b9618332]
#mycode2(){{
validates :size, inclusion: { in: %w(small medium large),  message: "%{value} のサイズは無効です" }
}}

*** 一意チェック(uniqueness) [#d26c5baa]
#mycode2(){{
validates :name, uniqueness: true
}}

*** バリデーション専用の別クラスでチェック(validates_with) [#y85a8742]
#mycode2(){{
validates_with MyValidator
}}
※ 後述([[バリデーション専用クラスを使用する>#kaedd690]])

*** バリデーションオプション [#z272ddfc]
共通のオプションとして allow_nil、allow_blank、message、on が使用可能。
|オプション|説明|h
|allow_nil|値がnilの場合にバリデーションをスキップする|
|allow_blank|値がblank?の場合にバリデーションをスキップする(nil、空文字も含まれる)|
|message|カスタムエラーメッセージを指定する|
|on|バリデーション実行のタイミングを指定する|

#html(</div>)

&br;

** モデルのバリデーションをカスタマイズする [#r4c9d0ad]
#html(<div style="padding-left:20px;">)

*** カスタムバリデートを利用する [#g94e7c40]
#html(<div style="padding-left:10px;">)
#mycode2(){{
validate :my_validate

def my_validate
  if name == "TEST"
    errors.add(:name, "「TEST」は指定できません")
  end
end
}}
#html(</div>)

*** バリデーション専用クラスを使用する [#kaedd690]
#html(<div style="padding-left:10px;">)
validates_with を使用して別のバリデーション専用クラスで定義した内容でチェックする事が可能。

#mycode2(){{
class MyValidator < ActiveModel::Validator
  def validate(record)
    if record.name == "TEST"
      record.errors[:base] << "「TEST」は指定できません"
    end
  end
end
 
class Book < ActiveRecord::Base
  validates_with MyValidator
end
}}
#html(</div>)



#html(</div>)

&br;

** モデルのチェック処理を呼び出す [#o8c3bda6]
#mycode2(){{
@user.valid?(:create)
}}

&br;

** SQLを直接実行する [#rc364266]
※http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/DatabaseStatements.html
#mycode2(){{
@books = ActiveRecord::Base.connection.select_all("select * from books")
}}

&br;

** coffeescript、scss を手動ビルドする [#rc8292fc]
#html(<div style="padding-left:20px;">)
#myterm2(){{
rake assets:precompile
}}
※app/assets 配下の scss, coffee がコンパイル/minifyされ、public/assets 配下に配置される
#html(</div>)
&br;

** 古いassetの削除(3世代分は残る?) [#rc8292fc]
#html(<div style="padding-left:20px;">)
#myterm2(){{
rake assets:clean
}}
#html(</div>)
&br;

** 古いassetの削除(完全) [#rc8292fc]
#html(<div style="padding-left:20px;">)
#myterm2(){{
rake assets:clobber
}}
#html(</div>)
&br;

** assets のパスを確認する [#x74c993a]
#myterm2(){{
rails console
> Rails.application.config.assets.paths
}}

&br;

** テンプレートをカスタマイズする [#fbd16602]
#html(<div style="padding-left:20px;">)
以下のコマンドでテンプレートのコピーをプロジェクト(lib/template)配下に作成する
#myterm2(){{
rake rails:templates:copy
}}
あとは作成されたテンプレートを編集するだけ。
#html(</div>)

** ジェネレータを作成する [#v0cfa6d5]
#html(<div style="padding-left:20px;">)

*** ジェネレータを使用してジェネレータを作成 [#p46879c1]
#myterm2(){{
rails generate generator modelyml
      create  lib/generators/modelyml
      create  lib/generators/modelyml/modelyml_generator.rb
      create  lib/generators/modelyml/USAGE
      create  lib/generators/modelyml/templates
      invoke  test_unit
      create    test/lib/generators/modelyml_generator_test.rb
}}

*** ジェネレータのソースを編集 [#j418178f]

例としてモデルの列名をYMLに定義するジェネレータを作成してみる

lib/generators/modelyml/modelyml_generator.rb
#mycode2(){{
class ModelymlGenerator < Rails::Generators::NamedBase
  source_root File.expand_path('../templates', __FILE__)

  # 定義したメソッドが上から順番に実行される
  def makeyml

    #@name ... 1つ目の引数
    #@args ... 2つ目以降の引数

    model = Module.const_get(@name.classify)
    fields = model.fields

    yml = ""
    #yml += "ja:\n"
    #yml += "  " + "activerecord:\n"   # orm が activerecord の場合
    yml += "  mongoid:\n"       # orm が mongoid の場合
    yml += "    " + "models:\n"
    yml += "      " + model.name.downcase + ": \"" + model.name.downcase + "\"\n"
    yml += "    " + "attributes:\n"
    yml += "      " + model.name.downcase + ":\n"
    fields.each_key do | key |
      yml += "        " + key + ": " + "\"" + key + "\"\n"
    end 

    create_file("config/locales/models/" + model.name.downcase + "/en.yml", "en:\n" + yml)
    create_file("config/locales/models/" + model.name.downcase + "/ja.yml", "ja:\n" + yml)

  end 

end
}}

*** 作成したジェネレータを実行 [#j4b19721]

#myterm2(){{
rails g modelyml book
      <span class="green">create</span>  config/locales/models/book/en.yml
      <span class="green">create</span>  config/locales/models/book/ja.yml
}}

#html(</div>)

&br;

** Scaffoldをカスタマイズする [#v0cfa6d5]

[[RailsでScaffoldの実行内容をカスタマイズする]]


&br;
** YMLを読み込む [#l3bfdf90]
#html(<div style="padding-left:20px;">)
#mycode2(){{
yml_data = YAML.load_file(Rails.root.join("config/locales/ja.yml"))
}}
#html(</div>)

&br;

** turbolinks使用時に各ページの初期処理を定義するには [#fd83e83d]
#html(<div style="padding-left:20px;">)
turbolinks を使用しているとページ遷移しても 全体は読み込まれない(body配下だけ書き換えられる)為、onloadイベントやjquery の ready イベント等は発生せず、page:load イベントが発火する。
・・が、page:load だけでは、どのページが読み込まれたかは判断できない為、ページ毎に初期化イベントをハンドリングする為に、少し手を加える。

views/layout/application.html.erb
#mycode2(){{
 ・
 ・
<body id="<%= controller_name %>-<%= action_name %>">
 ・
 ・
}}

assets/javascripts/_common.coffee  ※jsのload順を調整する為に、共通系のjsは _(アンダーバー)で始まるファイル名にしておく等の考慮が必要
#mycode2(){{
pageInit = ->
    id = $("body").attr("id");
    $("#"+id).trigger("pageinit");

$(document).ready(pageInit)
$(document).on("page:load", pageInit)
}}

assets/javascripts/books.coffee
#mycode2(){{

###
初期表示(一覧) 
###
pageInitIndex = (e) ->
    console.info "books init pageinit!"

###
初期表示(詳細) 
###
pageInitEdit = (e) ->
    console.info "books edit pageinit!"

# ページ読込時(一覧)
$(document).on "pageinit", "#books-index", pageInitIndex

# ページ読込時(詳細)
$(document).on "pageinit", "#books-edit", pageInitEdit

}}

#html(</div>)
&br;

** ブレークポイントの設定 [#lde30d39]
#todo(pry-byebug2)

&br;


トップ   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS