Rails技術者認定試験(Silver)対策めも
※ 自分用のメモなのであしからず
覚えることが多い。。。
1. Rails 概要
Railsのコンポーネント
- Active Record
- ORM(Object Relational Mapper)
- クラス <-> テーブル, 属性 <-> カラム のマッピングを行う
- モデル間の関連を定義する
マイグレーション機能を提供する
Active Model
- Modelクラスのインターフェースを提供
- バリデーションやコールバックのサポート
Action Pack
- Action Dispatch
- リクエストの解析とルーティングを行う
- Action Controller
- Controllerのベースクラスを提供
- Action Dispatch
Action View
- ビューテンプレートのルックアップとレンダリングを行う
- HTMLフォームを組み立てるためのビューヘルパを提供
Action Mailer
- Eメールサービスを提供し、メールの送受信処理を行う
Active Support
ツール及びライブラリ
フレームワークのディレクトリ構成
root/ ├ app/ ... │ ├ assets/ │ │ ├ images/ ...画像ファイル │ │ ├ javascripts/ ...jsファイル │ │ └ sytlesheets/ ...cssファイル │ ├ controllers/ │ │ └ conserns/ ...共通コードの置き場所。Railsのデフォルトのロー ドパスに含まれる │ ├ helpers/ │ ├ mailers/ │ ├ models/ │ │ └ conserns/ ...共通コードの置き場所。Railsのデフォルトのロードパスに含まれる │ └ views/ ...テンプレートファイル置き場 │ │ └ layouts/ │ │ └ application.html.erb ...アプリケーション共通レイアウトテンプレート ├ bin/ ├ config/ │ ├ environments/ ...環境毎の設定ファイルを格納 │ ├ initilizers/ ...初期化処理を定義したファイルを格納 │ │ ├ backtrace_silencers.rb ... 例外バックトレースのフィルタ │ │ ├ filter_parameter_logging.rb ...ロギングから除外するパラメータ情報の条件 │ │ ├ inflections.rb ...単数形/複数形の変換ルール │ │ ├ mime_types.rb ...アプリケーションで使用できるコンテンツタイプ │ │ ├ secret_token.rb ...クッキーを署名するためのトークン情報とかAPIのトークンを記載 │ │ │ * v4.1以降は「config/secrets.yml」に移行 │ │ └ session_store.rb ...セッション保存のためのリソースファイル │ ├ locales/ ...辞書ファイルを格納 │ ├ secrets.yml ... config/initilizers/secret_token.rb を参考 │ └ routes.rb ...ルーティグ設定ファイル ├ db/ │ ├ migrate/ ...マイグレーションファイルを格納 │ ├ schema.rb ...スキーマ情報を定義したファイル │ └ seeds.rb 初期データを定義するファイル ├ lib/ ├ log/ ...アプリケーションのログファイル ├ public/ ...静的なファイル、コンパイルされたアセットファイル ├ test/ │ ├ fixtures/ ...フィクスチャファイルを格納 │ ├ │ └ ├ temp/ └ vendor/
railsコマンド
rails new
Usage: rails new APP_PATH [options] Options: -r, [--ruby=PATH] # Path to the Ruby binary of your choice # Default: /Users/makoto/.rbenv/versions/2.2.5/bin/ruby -m, [--template=TEMPLATE] # Path to some application template (can be a filesystem path or URL) [--skip-gemfile], [--no-skip-gemfile] # Don't create a Gemfile -B, [--skip-bundle], [--no-skip-bundle] # Don't run bundle install -G, [--skip-git], [--no-skip-git] # Skip .gitignore file [--skip-keeps], [--no-skip-keeps] # Skip source control .keep files -O, [--skip-active-record], [--no-skip-active-record] # Skip Active Record files -S, [--skip-sprockets], [--no-skip-sprockets] # Skip Sprockets files [--skip-spring], [--no-skip-spring] # Don't install Spring application preloader -d, [--database=DATABASE] # Preconfigure for selected database (options: mysql/oracle/postgresql/sqlite3/frontbase/ibm_db/sqlserver/jdbcmysql/jdbcsqlite3/jdbcpostgresql/jdbc) # Default: sqlite3 -j, [--javascript=JAVASCRIPT] # Preconfigure for selected JavaScript library # Default: jquery -J, [--skip-javascript], [--no-skip-javascript] # Skip JavaScript files [--dev], [--no-dev] # Setup the application with Gemfile pointing to your Rails checkout [--edge], [--no-edge] # Setup the application with Gemfile pointing to Rails repository [--skip-turbolinks], [--no-skip-turbolinks] # Skip turbolinks gem -T, [--skip-test-unit], [--no-skip-test-unit] # Skip Test::Unit files [--rc=RC] # Path to file containing extra configuration options for rails command [--no-rc], [--no-no-rc] # Skip loading of extra configuration options from .railsrc file Runtime options: -f, [--force] # Overwrite files that already exist -p, [--pretend], [--no-pretend] # Run but do not make any changes -q, [--quiet], [--no-quiet] # Suppress status output -s, [--skip], [--no-skip] # Skip files that already exist Rails options: -h, [--help], [--no-help] # Show this help message and quit -v, [--version], [--no-version] # Show Rails version number and quit Description: The 'rails new' command creates a new Rails application with a default directory structure and configuration at the path you specify. You can specify extra command-line arguments to be used every time 'rails new' runs in the .railsrc configuration file in your home directory. Note that the arguments specified in the .railsrc file don't affect the defaults values shown above in this help message. Example: rails new ~/Code/Ruby/weblog This generates a skeletal Rails installation in ~/Code/Ruby/weblog. See the README in the newly created application to get going.
よく使うオプションは-d
(データベースの指定)?
例) testAppを作成
$ rails new testApp create create README.rdoc create Rakefile create config.ru create .gitignore create Gemfile create app create app/assets/javascripts/application.js create app/assets/stylesheets/application.css create app/controllers/application_controller.rb create app/helpers/application_helper.rb create app/views/layouts/application.html.erb create app/assets/images/.keep create app/mailers/.keep create app/models/.keep create app/controllers/concerns/.keep create app/models/concerns/.keep create bin create bin/bundle create bin/rails create bin/rake create bin/setup create config create config/routes.rb create config/application.rb create config/environment.rb create config/secrets.yml create config/environments create config/environments/development.rb create config/environments/production.rb create config/environments/test.rb create config/initializers create config/initializers/assets.rb create config/initializers/backtrace_silencers.rb create config/initializers/cookies_serializer.rb create config/initializers/filter_parameter_logging.rb create config/initializers/inflections.rb create config/initializers/mime_types.rb create config/initializers/session_store.rb create config/initializers/wrap_parameters.rb create config/locales create config/locales/en.yml create config/boot.rb create config/database.yml create db create db/seeds.rb create lib create lib/tasks create lib/tasks/.keep create lib/assets create lib/assets/.keep create log create log/.keep create public create public/404.html create public/422.html create public/500.html create public/favicon.ico create public/robots.txt create test/fixtures create test/fixtures/.keep create test/controllers create test/controllers/.keep create test/mailers create test/mailers/.keep create test/models create test/models/.keep create test/helpers create test/helpers/.keep create test/integration create test/integration/.keep create test/test_helper.rb create tmp/cache create tmp/cache/assets create vendor/assets/javascripts create vendor/assets/javascripts/.keep create vendor/assets/stylesheets create vendor/assets/stylesheets/.keep run bundle install Fetching gem metadata from https://rubygems.org/ Fetching version metadata from https://rubygems.org/ Fetching dependency metadata from https://rubygems.org/ Resolving dependencies..... Installing rake 11.1.2 Using i18n 0.7.0 Installing json 1.8.3 with native extensions Installing minitest 5.9.0 Using thread_safe 0.3.5 Using builder 3.2.2 Using erubis 2.7.0 Using mini_portile2 2.1.0 Using pkg-config 1.1.7 Using rack 1.6.4 Using mime-types-data 3.2016.0521 Using arel 6.0.3 Installing debug_inspector 0.0.2 with native extensions Using bundler 1.12.5 Installing byebug 9.0.5 with native extensions Installing coffee-script-source 1.10.0 Installing execjs 2.7.0 Using thor 0.19.1 Using concurrent-ruby 1.0.2 Installing multi_json 1.12.1 Installing sass 3.4.22 Installing tilt 2.0.5 Installing spring 1.7.1 Installing sqlite3 1.3.11 with native extensions Installing rdoc 4.2.2 Using tzinfo 1.2.2 Using nokogiri 1.6.8 Using rack-test 0.6.3 Using mime-types 3.1 Installing binding_of_caller 0.7.2 with native extensions Installing coffee-script 2.4.1 Installing uglifier 3.0.0 Using sprockets 3.6.0 Installing sdoc 0.4.1 Using activesupport 4.2.6 Using loofah 2.0.3 Using mail 2.6.4 Using rails-deprecated_sanitizer 1.0.3 Using globalid 0.3.6 Using activemodel 4.2.6 Installing jbuilder 2.5.0 Using rails-html-sanitizer 1.0.3 Using rails-dom-testing 1.0.7 Using activejob 4.2.6 Using activerecord 4.2.6 Using actionview 4.2.6 Using actionpack 4.2.6 Using actionmailer 4.2.6 Using railties 4.2.6 Using sprockets-rails 3.0.4 Installing coffee-rails 4.1.1 Installing jquery-rails 4.1.1 Using rails 4.2.6 Installing sass-rails 5.0.4 Installing web-console 2.3.0 Installing turbolinks 2.5.3 Bundle complete! 12 Gemfile dependencies, 56 gems now installed. Use `bundle show [gemname]` to see where a bundled gem is installed. Post-install message from rdoc: Depending on your version of ruby, you may need to install ruby rdoc/ri data: <= 1.8.6 : unsupported = 1.8.7 : gem install rdoc-data; rdoc-data --install = 1.9.1 : gem install rdoc-data; rdoc-data --install >= 1.9.2 : nothing to do! Yay! run bundle exec spring binstub --all * bin/rake: spring inserted * bin/rails: spring inserted
rails generate
モデルやコントローラなどのテンプレートを作成する。
$ rails generate -h Running via Spring preloader in process 77105 Usage: rails generate GENERATOR [args] [options] General options: -h, [--help] # Print generator's options and usage -p, [--pretend] # Run but do not make any changes -f, [--force] # Overwrite files that already exist -s, [--skip] # Skip files that already exist -q, [--quiet] # Suppress status output Please choose a generator below. Rails: assets controller generator helper integration_test jbuilder job mailer migration model resource scaffold scaffold_controller task Coffee: coffee:assets Js: js:assets TestUnit: test_unit:generator test_unit:job test_unit:plugin
例) コントローラの作成
$ rails generate controller test Running via Spring preloader in process 77709 create app/controllers/test_controller.rb invoke erb create app/views/test invoke test_unit create test/controllers/test_controller_test.rb invoke helper create app/helpers/test_helper.rb invoke test_unit invoke assets invoke coffee create app/assets/javascripts/test.coffee invoke scss create app/assets/stylesheets/test.scss
rails destroy
rails generateで作成したテンプレートを削除する。
$ rails destroy -h Running via Spring preloader in process 77128 Usage: rails destroy GENERATOR [args] [options] General options: -h, [--help] # Print generator's options and usage -p, [--pretend] # Run but do not make any changes -f, [--force] # Overwrite files that already exist -s, [--skip] # Skip files that already exist -q, [--quiet] # Suppress status output Please choose a generator below. Rails: assets controller generator helper integration_test jbuilder job mailer migration model resource scaffold scaffold_controller task Coffee: coffee:assets Js: js:assets TestUnit: test_unit:generator test_unit:job test_unit:plugin
例) コントローラの削除
$ rails destroy controller test Running via Spring preloader in process 77727 remove app/controllers/test_controller.rb invoke erb remove app/views/test invoke test_unit remove test/controllers/test_controller_test.rb invoke helper remove app/helpers/test_helper.rb invoke test_unit invoke assets invoke coffee remove app/assets/javascripts/test.coffee invoke scss remove app/assets/stylesheets/test.scss
rails server
Webサーバーを起動し、アプリケーションを実行する。
デフォルトのWebサーバはWEBrickで、そのほかにもmongrelやthinが使える。
$ rails server -h Usage: rails server [mongrel, thin etc] [options] -p, --port=port Runs Rails on the specified port. Default: 3000 -b, --binding=IP Binds Rails to the specified IP. Default: localhost -c, --config=file Uses a custom rackup configuration. -d, --daemon Runs server as a Daemon. -u, --debugger Enables the debugger. -e, --environment=name Specifies the environment to run this server under (test/development/production). Default: development -P, --pid=pid Specifies the PID file. Default: tmp/pids/server.pid -h, --help Shows this help message.
rails console
Railsアプリケーションの環境上で、対話的にRubyコードを実行する(irbが起動する)。
$ rails console -h Running via Spring preloader in process 77177 Usage: rails console [environment] [options] -s, --sandbox Rollback database modifications on exit. -e, --environment=name Specifies the environment to run this console under (test/development/production). Default: development --debugger Enables the debugger.
rails dbconsole
使用しているデータベースのコマンドラインツールを起動する。
$ rails dbconsole -h Usage: rails dbconsole [environment] [options] -p, --include-password Automatically provide the password from database.yml --mode [MODE] Automatically put the sqlite3 database in the specified mode (html, list, line, column). --header -h, --help Show this help message. -e, --environment=name Specifies the environment to run this console under (test/development/production). Default: development
rails runner
Railsアプリケーションの環境上で、非対話的にRubyコードを実行する。
$ rails runner -h Running via Spring preloader in process 77209 Usage: rails runner [options] [<'Some.ruby(code)'> | <filename.rb>] -e, --environment=name Specifies the environment for the runner to operate under (test/development/production). Default: development -h, --help Show this help message. Examples: rails runner 'puts Rails.env' This runs the code `puts Rails.env` after loading the app rails runner path/to/filename.rb This runs the Ruby file located at `path/to/filename.rb` after loading the app You can also use runner as a shebang line for your executables: ------------------------------------------------------------- #!/usr/bin/env /Users/makoto/Documents/src/Rails/testApp/rails_runner runner Product.all.each { |p| p.price *= 2 ; p.save! } -------------------------------------------------------------
例)
# 'hoge'と出力 $ rails runner 'puts "hoge"' Running via Spring preloader in process 77620 hoge # 環境設定を出力 $ rails runner 'puts Rails.env' Running via Spring preloader in process 77634 development
rake
RakeとはUNIXのMakeに相当するRubyのビルドツール。
$ rake -h rake [-f rakefile] {options} targets... Options are ... --backtrace=[OUT] Enable full backtrace. OUT can be stderr (default) or stdout. --comments Show commented tasks only --job-stats [LEVEL] Display job statistics. LEVEL=history displays a complete job list --rules Trace the rules resolution. --suppress-backtrace PATTERN Suppress backtrace lines matching regexp PATTERN. Ignored if --trace is on. -A, --all Show all tasks, even uncommented ones (in combination with -T or -D) -B, --build-all Build all prerequisites, including those which are up-to-date. -D, --describe [PATTERN] Describe the tasks (matching optional PATTERN), then exit. -e, --execute CODE Execute some Ruby code and exit. -E, --execute-continue CODE Execute some Ruby code, then continue with normal task processing. -f, --rakefile [FILENAME] Use FILENAME as the rakefile to search for. -G, --no-system, --nosystem Use standard project Rakefile search paths, ignore system wide rakefiles. -g, --system Using system wide (global) rakefiles (usually '~/.rake/*.rake'). -I, --libdir LIBDIR Include LIBDIR in the search path for required modules. -j, --jobs [NUMBER] Specifies the maximum number of tasks to execute in parallel. (default is number of CPU cores + 4) -m, --multitask Treat all tasks as multitasks. -n, --dry-run Do a dry run without executing actions. -N, --no-search, --nosearch Do not search parent directories for the Rakefile. -P, --prereqs Display the tasks and dependencies, then exit. -p, --execute-print CODE Execute some Ruby code, print the result, then exit. -q, --quiet Do not log messages to standard output. -r, --require MODULE Require MODULE before executing rakefile. -R, --rakelibdir RAKELIBDIR, Auto-import any .rake files in RAKELIBDIR. (default is 'rakelib') --rakelib -s, --silent Like --quiet, but also suppresses the 'in directory' announcement. -t, --trace=[OUT] Turn on invoke/execute tracing, enable full backtrace. OUT can be stderr (default) or stdout. -T, --tasks [PATTERN] Display the tasks (matching optional PATTERN) with descriptions, then exit. -v, --verbose Log message to standard output. -V, --version Display the program version. -W, --where [PATTERN] Describe the tasks (matching optional PATTERN), then exit. -X, --no-deprecation-warnings Disable the deprecation warnings. -h, -H, --help Display this help message.
タスクの一覧表示
$ rake -T rake about # List versions of all Rails frameworks and the environment rake assets:clean[keep] # Remove old compiled assets rake assets:clobber # Remove compiled assets rake assets:environment # Load asset compile environment rake assets:precompile # Compile all the assets named in config.assets.precompile rake cache_digests:dependencies # Lookup first-level dependencies for TEMPLATE (like messages/show or comments/_comment.html) rake cache_digests:nested_dependencies # Lookup nested dependencies for TEMPLATE (like messages/show or comments/_comment.html) rake db:create # Creates the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:crea... rake db:drop # Drops the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:drop:a... rake db:fixtures:load # Load fixtures into the current environment's database rake db:migrate # Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog) rake db:migrate:status # Display status of migrations rake db:rollback # Rolls the schema back to the previous version (specify steps w/ STEP=n) rake db:schema:cache:clear # Clear a db/schema_cache.dump file rake db:schema:cache:dump # Create a db/schema_cache.dump file rake db:schema:dump # Create a db/schema.rb file that is portable against any DB supported by AR rake db:schema:load # Load a schema.rb file into the database rake db:seed # Load the seed data from db/seeds.rb rake db:setup # Create the database, load the schema, and initialize with the seed data (use db:reset to also drop t... rake db:structure:dump # Dump the database structure to db/structure.sql rake db:structure:load # Recreate the databases from the structure.sql file rake db:version # Retrieves the current schema version number rake doc:app # Generate docs for the app -- also available doc:rails, doc:guides (options: TEMPLATE=/rdoc-template.... rake log:clear # Truncates all *.log files in log/ to zero bytes (specify which logs with LOGS=test,development) rake middleware # Prints out your Rack middleware stack rake notes # Enumerate all annotations (use notes:optimize, :fixme, :todo for focus) rake notes:custom # Enumerate a custom annotation, specify with ANNOTATION=CUSTOM rake rails:template # Applies the template supplied by LOCATION=(/path/to/template) or URL rake rails:update # Update configs and some other initially generated files (or use just update:configs or update:bin) rake routes # Print out all defined routes in match order, with names rake secret # Generate a cryptographically secure secret key (this is typically used to generate a secret for cook... rake stats # Report code statistics (KLOCs, etc) from the application or engine rake test # Runs all tests in test folder rake test:all # Run tests quickly by merging all types and not resetting db rake test:all:db # Run tests quickly, but also reset db rake test:db # Run tests quickly, but also reset db rake time:zones:all # Displays all time zones, also available: time:zones:us, time:zones:local -- filter with OFFSET param... rake tmp:clear # Clear session, cache, and socket files from tmp/ (narrow w/ tmp:sessions:clear, tmp:cache:clear, tmp... rake tmp:create # Creates tmp directories for sessions, cache, sockets, and pids
タスクの説明を表示
$ rake -D db:create rake db:create Creates the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:create:all to create all databases in the config). Without RAILS_ENV it defaults to creating the development and test databases.
rake routes
routes.rbに定義されたルーティング設定に基づき、URIパターン、対応するコントローラとアクションの一覧を表示する。
$ rake routes Prefix Verb URI Pattern Controller#Action blogs GET /blogs(.:format) blogs#index POST /blogs(.:format) blogs#create new_blog GET /blogs/new(.:format) blogs#new edit_blog GET /blogs/:id/edit(.:format) blogs#edit blog GET /blogs/:id(.:format) blogs#show PATCH /blogs/:id(.:format) blogs#update PUT /blogs/:id(.:format) blogs#update DELETE /blogs/:id(.:format) blogs#destroy
rake db:migrate
データベースのマイグレーション(移行)を実行する。
rake test
テストの実行。
引数なしでrake
を実行してもテストが実行される。
rake stats
アプリケーションのコードの統計を表示する。
$ rake stats +----------------------+-------+-------+---------+---------+-----+-------+ | Name | Lines | LOC | Classes | Methods | M/C | LOC/M | +----------------------+-------+-------+---------+---------+-----+-------+ | Controllers | 5 | 3 | 1 | 0 | 0 | 0 | | Helpers | 2 | 2 | 0 | 0 | 0 | 0 | | Models | 0 | 0 | 0 | 0 | 0 | 0 | | Mailers | 0 | 0 | 0 | 0 | 0 | 0 | | Javascripts | 18 | 0 | 0 | 0 | 0 | 0 | | Libraries | 0 | 0 | 0 | 0 | 0 | 0 | | Controller tests | 0 | 0 | 0 | 0 | 0 | 0 | | Helper tests | 0 | 0 | 0 | 0 | 0 | 0 | | Model tests | 0 | 0 | 0 | 0 | 0 | 0 | | Mailer tests | 0 | 0 | 0 | 0 | 0 | 0 | | Integration tests | 0 | 0 | 0 | 0 | 0 | 0 | +----------------------+-------+-------+---------+---------+-----+-------+ | Total | 25 | 5 | 1 | 0 | 0 | 0 | +----------------------+-------+-------+---------+---------+-----+-------+ Code LOC: 5 Test LOC: 0 Code to Test Ratio: 1:0.0
※ LOC: Line Of Code の略。コメントをのぞいた行数。
rake notes
ソースコード内のTODO、FIXME、OPTIMIZEコメントを抽出し、その行を表示する。
$ rake notes app/controllers/application_controller.rb: * [5] [TODO] rake notesのテストのため1 * [6] [FIXME] rake notesのテストのため2 * [7] [OPTIMIZE] rake notesのテストのため3
Active Support
参考
Active Support Core Extensions — Ruby on Rails Guides
Active Support コア拡張機能 | Rails ガイド
html_safe
html_escape (h)
harmful_string = '< > \' " & ' puts ERB::Util.html_escape(harmful_string) # < > ' " & # hがhtml_escapeのエイリアスとして割り当てられているので、下記でもOK # puts ERB::Util.h(harmful_string)
html_safe?
実際にエスケープされているかどうかは分からない
html_escape
によってエスケープされた文字はhtml_safe?でtrueが返る
blank?
レシーバがブランクの場合、trueを返す。
なお、レシーバが以下の場合、ブランクとみなされる。
- nilとfalse
- 空白文字 (whitespace) だけで構成された文字列 (※1, ※2)
- 空欄の配列とハッシュ
- その他、empty?メソッドに応答するオブジェクトはすべて空白として扱われる
※1 文字列を判定する述語として、Unicode対応した文字クラスである[:space:]が使用されています。そのため、たとえばU+2029 (段落区切り文字)は空白文字と判断される。
※2 数字については空白であるかどうかは判断されません。特に0および0.0は空白ではないことに注意。
{}.blank? # => true [].blank? # => true nil.blank? # => true false.blank? # => true # 数値はblank?でtrueを返すことはない 0.blank? # => false
present?
blank?の逆。
presence
presence? がtrueの場合、レシーバを返す。
falseの場合、nilを返す。
''.presence # => nil 'hoge'.presence # => hoge
duplicable?
レシーバがシングルトンインスタンスの場合、falseを返す。
"foo".duplicable? # => true "".duplicable? # => true 0.0.duplicable? # => false false.duplicable? # => false
try
レシーバがnilでない時だけ、引数に渡したメソッドを呼び出す
num = nil num.try :to_s # => to_s は呼ばれない num = 1 num.try :to_s # => "1"
in?
レシーバに引数が含まれていればtrueを返す。
引数に渡したオブジェクトがinclue?メソッドを持たない場合、ArgumentErrorが発生する
1.in?([1,2]) # true "lo".in?("hello") # true 25.in?(30..50) # false 1.in?(1) # ArgumentError # 引数がハッシュの場合、キーが検索対象 'key'.in?({ 'key' => 'val' }) # true 'val'.in?({ 'key' => 'val' }) # false
delegate
他のオブジェクトのメソッドを移譲する。
class Greeter < ActiveRecord::Base def hello 'hello' end def goodbye 'goodbye' end end class Foo < ActiveRecord::Base belongs_to :greeter delegate :hello, to: :greeter end Foo.new.hello # => "hello" Foo.new.goodbye # => NoMethodError: undefined method `goodbye' for #<Foo:0x1af30c>
cattr_accessor
クラス変数のアクセサを定義する。
実体はmattr_accessorのエイリアス。
stringの拡張
remove
str = "Hello World" str.remove(/Hello /) # => "World" # str自体は操作されない
remove!
removeの破壊的メソッド
squish
冒頭と末尾のホワイトスペースを除去し、連続したホワイトスペースを1つに減らす
" \n foo\n\r \t bar \n".squish # => "foo bar"
squish!
squishの破壊的メソッド
truncate(truncate_at, options = {})
# デフォルトのomissionは''(空文字) '123456789 123456789 123456789'.truncate(10) # => "1234567..." '1234 6789 123456789 123456789'.truncate(10, separator: ' ') # => "1234..." # omissionの指定例 '1234 6789 123456789 123456789'.truncate(10, omission: '') # => "1234 6789 "
truncate_words(words_count, options = {})
'Once upon a time in a world far far away'.truncate_words(4) # => "Once upon a time..."
options
- omission
- separator
starts_with?とends_with?
String#start_with?とString#end_with?のエイリアス(英語的に自然な三人称にしている)
at(position)
"hello".at(0) # => "h" "hello".at(4) # => "o" "hello".at(-1) # => "o" "hello".at(10) # => nil
from(position)
"hello".from(0) # => "hello" "hello".from(2) # => "llo" "hello".from(-2) # => "lo" "hello".from(10) # => nil
to(position)
"hello".to(0) # => "h" "hello".to(2) # => "hel" "hello".to(-2) # => "hell" "hello".to(10) # => "hello"
first(limit = 1)
"hello".first(2) # => "he" # to(-2)と等価
last(limit = 1)
"hello".last(2) # => "lo" # from(-2) と等価
pluralize(count = nil, locale = :en)
複数形に変換にして返す。
"cap".pluralize # => "caps" "knife".pluralize # => "knives"
定義は config/initializers/inflections.rb で可能
singularize(locale = :en)
pluralize
の逆
camelize(first_letter = :upper)
スネークケースをキャメルケースにして返す。
なお、 /
は::
に置き換えられる。
'active_record'.camelize # => "ActiveRecord" 'active_record'.camelize(:lower) # => "activeRecord" 'active_record/errors'.camelize # => "ActiveRecord::Errors" 'active_record/errors'.camelize(:lower) # => "activeRecord::Errors"
camelcase
のエイリアス
underscore()
キャメルケースをスネークケースにして返す。
なお、::
は/
に置き換えられる。
'ActiveModel'.underscore # => "active_model" 'ActiveModel::Errors'.underscore # => "active_model/errors"
titleize()
dasherize(underscored_word)
demodulize()
'ActiveRecord::CoreExtensions::String::Inflections'.demodulize # => "Inflections" 'Inflections'.demodulize # => "Inflections" '::Inflections'.demodulize # => "Inflections" ''.demodulize # => ''
deconstantize
parameterize
tableize
underscore
の次にpluralize
を実行したもの
classify
tableize
と逆の動作
humanize(options = {})
- 引数に (英語の) 活用ルールを適用します(inflection)。
- 冒頭にアンダースコアがある場合は削除します。
- 末尾に"_id"がある場合は削除します。
- アンダースコアが他にもある場合はスペースに置き換えます。
- 略語を除いてすべての単語を小文字にします(downcase)。
- 最初の単語だけ冒頭の文字を大文字にします(capitalize)。
'employee_salary'.humanize # => "Employee salary" 'author_id'.humanize # => "Author" 'author_id'.humanize(capitalize: false) # => "author" '_id'.humanize # => "Id"
to_date()
"1-1-2012".to_date # => Sun, 01 Jan 2012 "01/01/2012".to_date # => Sun, 01 Jan 2012 "2012-12-13".to_date # => Thu, 13 Dec 2012 "12/13/2012".to_date # => ArgumentError: invalid date
to_datetime()
"1-1-2012".to_datetime # => Sun, 01 Jan 2012 00:00:00 +0000 "01/01/2012 23:59:59".to_datetime # => Sun, 01 Jan 2012 23:59:59 +0000 "2012-12-13 12:50".to_datetime # => Thu, 13 Dec 2012 12:50:00 +0000 "12/13/2012".to_datetime # => ArgumentError: invalid date
to_time(form = :local)
"13-12-2012".to_time # => 2012-12-13 00:00:00 +0100 "06:12".to_time # => 2012-12-13 06:12:00 +0100 "2012-12-13 06:12".to_time # => 2012-12-13 06:12:00 +0100 "2012-12-13T06:12".to_time # => 2012-12-13 06:12:00 +0100 "2012-12-13T06:12".to_time(:utc) # => 2012-12-13 06:12:00 UTC "2012-12-13T06:12".to_time(:jst) # => 2012-12-13 06:12:00 +0900 "12/13/2012".to_time # => ArgumentError: argument out of range
Numericの拡張
バイト
2.kilobytes # => 2048 3.megabytes # => 3145728 3.5.gigabytes # => 3758096384 -4.exabytes # => -4611686018427387904
それぞれ単数系のエイリアスがある
1.megabyte # => 1048576 # レシーバが1より多くても問題無い 2.megabyte # => 2097152
Time
# Time.current.advance(months: 1) と等価 1.month.from_now # Time.current.advance(years: 2) と等価 2.years.from_now # Time.current.advance(months: 4, years: 5) と等価 (4.months + 5.years).from_now
to_s(*args)
Phone Numbers: 5551234.to_s(:phone) # => "555-1234" 1235551234.to_s(:phone) # => "123-555-1234" 1235551234.to_s(:phone, area_code: true) # => "(123) 555-1234" 1235551234.to_s(:phone, delimiter: ' ') # => "123 555 1234" 1235551234.to_s(:phone, area_code: true, extension: 555) # => "(123) 555-1234 x 555" 1235551234.to_s(:phone, country_code: 1) # => "+1-123-555-1234" 1235551234.to_s(:phone, country_code: 1, extension: 1343, delimiter: '.') # => "+1.123.555.1234 x 1343" Currency: 1234567890.50.to_s(:currency) # => "$1,234,567,890.50" 1234567890.506.to_s(:currency) # => "$1,234,567,890.51" 1234567890.506.to_s(:currency, precision: 3) # => "$1,234,567,890.506" 1234567890.506.to_s(:currency, locale: :fr) # => "1 234 567 890,51 €" -1234567890.50.to_s(:currency, negative_format: '(%u%n)') # => "($1,234,567,890.50)" 1234567890.50.to_s(:currency, unit: '£', separator: ',', delimiter: '') # => "£1234567890,50" 1234567890.50.to_s(:currency, unit: '£', separator: ',', delimiter: '', format: '%n %u') # => "1234567890,50 £" Percentage: 100.to_s(:percentage) # => "100.000%" 100.to_s(:percentage, precision: 0) # => "100%" 1000.to_s(:percentage, delimiter: '.', separator: ',') # => "1.000,000%" 302.24398923423.to_s(:percentage, precision: 5) # => "302.24399%" 1000.to_s(:percentage, locale: :fr) # => "1 000,000%" 100.to_s(:percentage, format: '%n %') # => "100.000 %" Delimited: 12345678.to_s(:delimited) # => "12,345,678" 12345678.05.to_s(:delimited) # => "12,345,678.05" 12345678.to_s(:delimited, delimiter: '.') # => "12.345.678" 12345678.to_s(:delimited, delimiter: ',') # => "12,345,678" 12345678.05.to_s(:delimited, separator: ' ') # => "12,345,678 05" 12345678.05.to_s(:delimited, locale: :fr) # => "12 345 678,05" 98765432.98.to_s(:delimited, delimiter: ' ', separator: ',') # => "98 765 432,98" Rounded: 111.2345.to_s(:rounded) # => "111.235" 111.2345.to_s(:rounded, precision: 2) # => "111.23" 13.to_s(:rounded, precision: 5) # => "13.00000" 389.32314.to_s(:rounded, precision: 0) # => "389" 111.2345.to_s(:rounded, significant: true) # => "111" 111.2345.to_s(:rounded, precision: 1, significant: true) # => "100" 13.to_s(:rounded, precision: 5, significant: true) # => "13.000" 111.234.to_s(:rounded, locale: :fr) # => "111,234" 13.to_s(:rounded, precision: 5, significant: true, strip_insignificant_zeros: true) # => "13" 389.32314.to_s(:rounded, precision: 4, significant: true) # => "389.3" 1111.2345.to_s(:rounded, precision: 2, separator: ',', delimiter: '.') # => "1.111,23" # Human-friendly size in Bytes: 123.to_s(:human_size) # => "123 Bytes" 1234.to_s(:human_size) # => "1.21 KB" 12345.to_s(:human_size) # => "12.1 KB" 1234567.to_s(:human_size) # => "1.18 MB" 1234567.to_s(:human_size, precision: 2) # => "1.2 MB" 1234567890.to_s(:human_size) # => "1.15 GB" 1234567890123.to_s(:human_size) # => "1.12 TB" 1234567890123.to_s(:human_size, precision: 5) # => "1.1228 TB" 1234567890123456.to_s(:human_size) # => "1.1 PB" 1234567890123456789.to_s(:human_size) # => "1.07 483989.to_s(:human_size) # => "473 KB" 483989.to_s(:human_size, precision: 2) # => "470 KB" 1234567.to_s(:human_size, precision: 2, separator: ',') # => "1,2 MB" 524288000.to_s(:human_size) # => "500 MB" 524288000.to_s(:human_size, precision: 5) # => "500 MB" # Human-friendly format: 123.to_s(:human) # => "123" 1234.to_s(:human) # => "1.23 Thousand" 12345.to_s(:human) # => "12.3 Thousand" 1234567.to_s(:human) # => "1.23 Million" 1234567890.to_s(:human) # => "1.23 Billion" 1234567890123.to_s(:human) # => "1.23 Trillion" 1234567890123456.to_s(:human) # => "1.23 Quadrillion" 1234567890123456789.to_s(:human) # => "1230 Quadrillion" 489939.to_s(:human, precision: 2) # => "490 Thousand" 489939.to_s(:human, precision: 4) # => "489.9 Thousand" 1234567.to_s(:human, precision: 4, significant: false) # => "1.2346 Million" 1234567.to_s(:human, precision: 1, separator: ',', significant: false) # => "1,2 Million"
Integerの拡張
ordinalize()
1.ordinalize # => "1st" 2.ordinalize # => "2nd" 53.ordinalize # => "53rd" 2009.ordinalize # => "2009th" -21.ordinalize # => "-21st" -134.ordinalize # => "-134th"
Enumerableの拡張
sum
[1, 2, 3].sum # => 6 (1..100).sum # => 5050 [[1, 2], [2, 3], [3, 4]].sum # => [1, 2, 2, 3, 3, 4] %w(foo bar baz).sum # => "foobarbaz" {a: 1, b: 2, c: 3}.sum # => [:b, 2, :c, 3, :a, 1] [].sum # => 0 (1..5).sum {|n| n * 2 } # => 30 # [2, 4, 6, 8, 10].sum # => 30
many?
# collection.size > 1 [1].many? # => false [1, 2].many? => true [1, 2, 3].many? {|n| n > 2} # => false [1, 2, 3].many? {|n| n > 1} # => true
exclude?
include?
の逆
without
["David", "Rafael", "Aaron", "Todd"].without("Aaron", "Todd") # => ["David", "Rafael"]
Arrayの拡張
Accessing
# to %w(a b c d).to(2) # => %w(a b c) [].to(7) # => [] # from %w(a b c d).from(2) # => %w(c d) %w(a b c d).from(10) # => [] [].from(0) # => [] %w(a b c d).third # => c %w(a b c d).fifth # => nil
append
Array#<<
のエイリアス
%w(a b c d).append('e') # => %w(a b c d e) [].append([1,2]) # => [[1,2]]
prepend
Array#unshift
のエイリアス
%w(a b c d).prepend('e') # => %w(e a b c d) [].prepend(10) # => [10]
その他
to_sentence
to_formatted_s
to_xml
設定
設定ファイルのパラメータ
分類 | パラメータ名 | 概要 | デフォルト |
---|---|---|---|
基本 | cache_classes | アプリケーションクラスのリロードをするか | develpment = false test = false production = true |
cache_store | キャッシュの保存先 | ||
colorize_logging | ログ情報をカラーリングするか | true | |
autoload_paths | オートロード対象となるパス | ||
asset_host | Assetヘルパーで付与するホスト名 | ||
log_level | ログレベル | develpment = :debug test = :debug production = :info |
|
logger | 使用するロガー | ||
time_zone | アプリケーションやActiveRecordで利用するタイムゾーン | :local | |
i18n.default_locale | 国際化対応で利用するデフォルトのロケール | :en | |
Active Record | active_record.logger | 利用するロガー | |
active_record.schema_format | スキーマのダンプ形式 | :ruby | |
active_record.timestamped_migrations | マイグレーションファイルをタイムスタンプで管理するか | true | |
Action Controller | action_controller.default_charset | デフォルトの文字コード | utf-8 |
action_controller.logger | 利用するロガー | ||
action_controller.perform_caching | キャッシュ機能を有効にするか | develpment = false test = false production = true |
|
session_store | セッション格納するストア名 | ||
Action View | action_view.default_form_builder | デフォルトで利用されるフォームビルダ | |
action_view.logger | 利用するロガー | ||
action_view.field_error_proc | エラー時に入力要素を括るタグ | Proc.new do | html_tag, instance | %Q( #{html_tag} ).html_safeend |
2. Active Record
Modelの生成
rails generate model
$ rails generate model -h Running via Spring preloader in process 80982 Usage: rails generate model NAME [field[:type][:index] field[:type][:index]] [options] Options: [--skip-namespace], [--no-skip-namespace] # Skip namespace (affects only isolated applications) [--force-plural], [--no-force-plural] # Forces the use of the given model name -o, --orm=NAME # Orm to be invoked # Default: active_record ActiveRecord options: [--migration], [--no-migration] # Indicates when to generate migration # Default: true [--timestamps], [--no-timestamps] # Indicates when to generate timestamps # Default: true [--parent=PARENT] # The parent class for the generated model [--indexes], [--no-indexes] # Add indexes for references and belongs_to columns # Default: true -t, [--test-framework=NAME] # Test framework to be invoked # Default: test_unit TestUnit options: [--fixture], [--no-fixture] # Indicates when to generate fixture # Default: true -r, [--fixture-replacement=NAME] # Fixture replacement to be invoked Runtime options: -f, [--force] # Overwrite files that already exist -p, [--pretend], [--no-pretend] # Run but do not make any changes -q, [--quiet], [--no-quiet] # Suppress status output -s, [--skip], [--no-skip] # Skip files that already exist Description: Stubs out a new model. Pass the model name, either CamelCased or under_scored, and an optional list of attribute pairs as arguments. Attribute pairs are field:type arguments specifying the model's attributes. Timestamps are added by default, so you don't have to specify them by hand as 'created_at:datetime updated_at:datetime'. As a special case, specifying 'password:digest' will generate a password_digest field of string type, and configure your generated model and tests for use with ActiveModel has_secure_password (assuming the default ORM and test framework are being used). You don't have to think up every attribute up front, but it helps to sketch out a few so you can start working with the model immediately. This generator invokes your configured ORM and test framework, which defaults to ActiveRecord and TestUnit. Finally, if --parent option is given, it's used as superclass of the created model. This allows you create Single Table Inheritance models. If you pass a namespaced model name (e.g. admin/account or Admin::Account) then the generator will create a module with a table_name_prefix method to prefix the model's table name with the module name (e.g. admin_accounts) Available field types: Just after the field name you can specify a type like text or boolean. It will generate the column with the associated SQL type. For instance: `rails generate model post title:string body:text` will generate a title column with a varchar type and a body column with a text type. If no type is specified the string type will be used by default. You can use the following types: integer primary_key decimal float boolean binary string text date time datetime You can also consider `references` as a kind of type. For instance, if you run: `rails generate model photo title:string album:references` It will generate an `album_id` column. You should generate these kinds of fields when you will use a `belongs_to` association, for instance. `references` also supports polymorphism, you can enable polymorphism like this: `rails generate model product supplier:references{polymorphic}` For integer, string, text and binary fields, an integer in curly braces will be set as the limit: `rails generate model user pseudo:string{30}` For decimal, two integers separated by a comma in curly braces will be used for precision and scale: `rails generate model product 'price:decimal{10,2}'` You can add a `:uniq` or `:index` suffix for unique or standard indexes respectively: `rails generate model user pseudo:string:uniq` `rails generate model user pseudo:string:index` You can combine any single curly brace option with the index options: `rails generate model user username:string{30}:uniq` `rails generate model product supplier:references{polymorphic}:index` If you require a `password_digest` string column for use with has_secure_password, you should specify `password:digest`: `rails generate model user password:digest` Examples: `rails generate model account` For ActiveRecord and TestUnit it creates: Model: app/models/account.rb Test: test/models/account_test.rb Fixtures: test/fixtures/accounts.yml Migration: db/migrate/XXX_create_accounts.rb `rails generate model post title:string body:text published:boolean` Creates a Post model with a string title, text body, and published flag. `rails generate model admin/account` For ActiveRecord and TestUnit it creates: Module: app/models/admin.rb Model: app/models/admin/account.rb Test: test/models/admin/account_test.rb Fixtures: test/fixtures/admin/accounts.yml Migration: db/migrate/XXX_create_admin_accounts.rb
例)Itemモデルの作成
$ rails generate model Item name:string:uniq price:integer Running via Spring preloader in process 80709 invoke active_record create db/migrate/20160609184609_create_items.rb # マイグレーション create app/models/item.rb # モデル invoke test_unit create test/models/item_test.rb # create test/fixtures/items.yml # フィクスチャ
生成されるマイグレーションファイル
class CreateItems < ActiveRecord::Migration def change create_table :items do |t| t.string :name t.integer :price t.timestamps null: false end add_index :items, :name, unique: true end end
フィールドのデータ型
データ型 |
---|
integer{limit} |
decimal{precision, scale} |
float |
test{limit} |
string{limit} |
date |
time |
datetime |
boolean |
binary{limit} |
primary_key |
references{polymorphic} |
インデックス
インデックス | 概要 |
---|---|
uniq | 一意性制約を追加 |
index | インデックスを追加 |
Modelクラスについて
- ActiveRecord::Baseクラスを継承する
例)app/models/item.rb
class Item < ActiveRecord::Base end
値の設定と保存
# モデルクラスのインスタンス化 Item item = Item.new # 値の設定 item.name = 'apple' item.price = 100 # 値をDBへ保存 item.save
CoC
種類 | 概要 | 例 |
---|---|---|
モデルクラス | キャメル(先頭大文字) | Book |
モデルクラス(ファイル名) | スネークケース(小文字) | book.rb |
テーブル名* | スネークケース(小文字) | books |
テストスクリプト名 | クラス名(先頭小文字)に接尾辞「_test.rb」 | book_test.rb |
* 複数形になっていることに注意
Finder Methods
find(*args)
- レコードが見つからないと
ActiveRecord::RecordNotFound
が発生 - 引数が単一の場合戻り値はモデル、配列の場合は
Array
オブジェクトが返る
Person.find(1) # returns the object for ID = 1 Person.find("1") # returns the object for ID = 1 Person.find("31-sarah") # returns the object for ID = 31 Person.find(1, 2, 6) # returns an array for objects with IDs in (1, 2, 6) Person.find([7, 17]) # returns an array for objects with IDs in (7, 17) Person.find([1]) # returns an array for the object with ID = 1 Person.where("administrator = 1").order("created_on DESC").find(1)
find_by(arg, *args)
- 単一のレコードを返す(複数ある場合、最初のレコードが返る)
- レコードが見つからない場合、
nil
が返る - 戻り値はモデルのオブジェクト
find_by!(arg, *args)
- レコードが見つからない場合、
ActiveRecord::RecordNotFound
が発生する - 上記以外は
find_by(arg, *args)
と同じ
find_by_sql(sql, binds = [], preparable: nil)
- 戻り値は
Array
のオブジェクト - レコードが見つからない場合、空の
Array
first(limit = nil)
- 引数がないまたは
nil
の場合、モデルのオブジェクトが返る - 引数があり、
nil
でない場合、Array
のオブジェクトが返る
Book.select(:id, :title).first # Book Load (0.1ms) SELECT "books"."id", "books"."title" FROM "books" ORDER BY "books"."id" ASC LIMIT 1 # #<Book:0x007ff04b22c250 id: 1, title: "AndroidエンジニアのためのモダンJava"> Book.select(:id, :title).first 3 # Book Load (0.1ms) SELECT "books"."id", "books"."title" FROM "books" ORDER BY "books"."id" ASC LIMIT 3 # [#<Book:0x007ff04ca5a818 id: 1, title: "AndroidエンジニアのためのモダンJava">, # <Book:0x007ff04ca5a688 id: 2, title: "JavaScriptライブラリ実践活用">, # <Book:0x007ff04ca5a4f8 id: 3, title: "Ruby on Rails 4ポケットリファレンス">]
last(limit = nil)
exists?(conditions = :none)
- Integer - Finds the record with this primary key.
- String - Finds the record with a primary key corresponding to this string (such as '5').
- Array - Finds the record that matches these find-style conditions (such as ['name LIKE ?', "%#{query}%"]).
- Hash - Finds the record that matches these find-style conditions (such as {name: 'David'}).
- false - Returns always false.
- No args - Returns false if the table is empty, true otherwise.
Person.exists?(5) Person.exists?('5') Person.exists?(['name LIKE ?', "%#{query}%"]) Person.exists?(id: [1, 4, 8]) Person.exists?(name: 'David') Person.exists?(false) Person.exists?
Query Methods
Query Methodの戻り値はActiveRecord_Relation
のオブジェクトとなる
where(opts = :chain, *rest)
### String Client.where("orders_count = '2'") # SELECT * from clients where orders_count = '2'; ### Array User.where(["name = ? and email = ?", "Joe", "joe@example.com"]) # SELECT * FROM users WHERE name = 'Joe' AND email = 'joe@example.com'; User.where(["name = :name and email = :email", { name: "Joe", email: "joe@example.com" }]) # SELECT * FROM users WHERE name = 'Joe' AND email = 'joe@example.com'; ### Hash User.where({ name: "Joe", email: "joe@example.com" }) # SELECT * FROM users WHERE name = 'Joe' AND email = 'joe@example.com' User.where({ name: ["Alice", "Bob"]}) # SELECT * FROM users WHERE name IN ('Alice', 'Bob') User.where({ created_at: (Time.now.midnight - 1.day)..Time.now.midnight }) # SELECT * FROM users WHERE (created_at BETWEEN '2012-06-09 07:00:00.000000' AND '2012-06-10 07:00:00.000000') Book.where id: 1...4 # SELECT "books".* FROM "books" WHERE ("books"."id" >= 1 AND "books"."id" < 4) Book.where id: 1..4 # SELECT "books".* FROM "books" WHERE ("books"."id" BETWEEN 1 AND 4)
not(opts, *rest)
- ActiveRecord::QueryMethods::WhereChainが呼び出すことができる
where
に引数を与えるとActiveRecord_Relation
が返るので、NoMethodError
が発生する
User.where.not("name = 'Jon'") # SELECT * FROM users WHERE NOT (name = 'Jon') User.where.not(["name = ?", "Jon"]) # SELECT * FROM users WHERE NOT (name = 'Jon') User.where.not(name: "Jon") # SELECT * FROM users WHERE name != 'Jon' User.where.not(name: nil) # SELECT * FROM users WHERE name IS NOT NULL User.where.not(name: %w(Ko1 Nobu)) # SELECT * FROM users WHERE name NOT IN ('Ko1', 'Nobu') User.where.not(name: "Jon", role: "admin") # SELECT * FROM users WHERE name != 'Jon' AND role != 'admin'
エラー例
User.where(name: 'Jon').not # => NoMethodErrorが発生 User.where.not(name: 'Jon') # => OK
order(*args)
### Symbol User.order(:name) # SELECT "users".* FROM "users" ORDER BY "users"."name" ASC ### Hash User.order(email: :desc) # SELECT "users".* FROM "users" ORDER BY "users"."email" DESC ### Array User.order(:name, email: :desc) # SELECT "users".* FROM "users" ORDER BY "users"."name" ASC, "users"."email" DESC ### String User.order('name') # SELECT "users".* FROM "users" ORDER BY name User.order('name DESC') # SELECT "users".* FROM "users" ORDER BY name DESC User.order('name DESC, email') # SELECT "users".* FROM "users" ORDER BY name DESC, email
reorder(*args)
reorder
を呼び出す前のorder
が破棄される点に注意
User.order('email DESC').reorder('id ASC') # order('email DESC')は破棄される # generated SQL has 'ORDER BY id ASC' User.order('email DESC').order('id ASC') # order('email DESC')は有効 # generated SQL has 'ORDER BY email DESC, id ASC'
select(*fields)
指定した列だけ取得する
Model.select(:field) # => [#<Model id: nil, field: "value">]
distinct
publishes = Book.select(:publish) #[#<Book:0x007ff04c7bbb48 id: nil, publish: "技術評論社">, #<Book:0x007ff04c7bb9e0 id: nil, publish: "技術評論社">, #<Book:0x007ff04c7bb878 id: nil, publish: "技術評論社">, #<Book:0x007ff04c7bb710 id: nil, publish: "日経BP社">, #<Book:0x007ff04c7bb5a8 id: nil, publish: "秀和システム">, #<Book:0x007ff04c7bb440 id: nil, publish: "翔泳社">, #<Book:0x007ff04c7bb288 id: nil, publish: "日経BP社">, #<Book:0x007ff04c7bb0f8 id: nil, publish: "翔泳社">, #<Book:0x007ff04c7baf90 id: nil, publish: "翔泳社">, #<Book:0x007ff04c7bae00 id: nil, publish: "ソシム">] publishes.distinct #[#<Book:0x007ff04c6aad08 id: nil, publish: "技術評論社">, #<Book:0x007ff04c6aab28 id: nil, publish: "日経BP社">, #<Book:0x007ff04c6aa920 id: nil, publish: "秀和システム">, #<Book:0x007ff04c6aa718 id: nil, publish: "翔泳社">, #<Book:0x007ff04c6aa560 id: nil, publish: "ソシム">] publishes.distinct false #[#<Book:0x007ff04bb25280 id: nil, publish: "技術評論社">, #<Book:0x007ff04bb24b50 id: nil, publish: "技術評論社">, #<Book:0x007ff04bb24538 id: nil, publish: "技術評論社">, #<Book:0x007ff04bb1fdf8 id: nil, publish: "日経BP社">, #<Book:0x007ff04bb1fa60 id: nil, publish: "秀和システム">, #<Book:0x007ff04bb1f498 id: nil, publish: "翔泳社">, #<Book:0x007ff04bb1f1f0 id: nil, publish: "日経BP社">, #<Book:0x007ff04bb1eed0 id: nil, publish: "翔泳社">, #<Book:0x007ff04bb1eb60 id: nil, publish: "翔泳社">, #<Book:0x007ff04bb1e638 id: nil, publish: "ソシム">] Book.distinct.pluck :publish # ["技術評論社", "日経BP社", "秀和システム", "翔泳社", "ソシム"]
limit(value)
offset(value)
Book.select(:id).limit(2).offset(5) # Book Load (0.1ms) SELECT "books"."id" FROM "books" LIMIT 2 OFFSET 5 # => [#<Book:0x007ff04b231020 id: 6>, #<Book:0x007ff04b230ee0 id: 7>]
group(*args)
books = Book.select('publish, AVG(price) AS avg_price').group(:publish) # SELECT publish, AVG(price) AS avg_price FROM "books" GROUP BY "books"."publish" books.each do |book| puts book.avg_price.to_s + "\t" + book.publish end # 2625.0 ソシム # 2996.0 技術評論社 # 2152.5 日経BP社 # 3150.0 秀和システム # 3283.0 翔泳社
having(opts, *rest)
books = Book.select('publish, SUM(price) AS sum_price').group(:publish).having('sum_price < 8000') books.each do |book| puts book.sum_price.to_s + '|' + book.publish end # 2625|ソシム # 4305|日経BP社 # 3150|秀和システム
unscope(*args)
User.order('email DESC').unscope(:order) # = User.all User.where(name: "John", active: true).unscope(where: :name) # = User.where(active: true)
none()
user = User.none user.class => User::ActiveRecord_Relation user.each => #<Enumerator: ...> user = nil user.each # NoMethodError: undefined method `each' for nil:NilClass
その他
find_each(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil)
options
- batch_size
- start
- finish
- error_on_ignore
※ finish
とerror_on_ignore
はバージョン5.0
から
# 2000件目から2000件ずつ処理 User.find_each(start: 2000, batch_size: 2000) do |user| # something to process end
pluck(*column_names)
指定した列の配列を取得する
Person.pluck(:name)
はPerson.all.map(&:name)
に置き換えられる- 上記の
map
を使う場合よりpluck
を使う方が4倍ほど早いらしい (ソース)
Person.pluck(:name) # SELECT people.name FROM people # => ['David', 'Jeremy', 'Jose'] Person.pluck(:id, :name) # SELECT people.id, people.name FROM people # => [[1, 'David'], [2, 'Jeremy'], [3, 'Jose']] Person.distinct.pluck(:role) # SELECT DISTINCT role FROM people # => ['admin', 'member', 'guest'] Person.where(age: 21).limit(5).pluck(:id) # SELECT people.id FROM people WHERE people.age = 21 LIMIT 5 # => [2, 3] Person.pluck('DATEDIFF(updated_at, created_at)') # SELECT DATEDIFF(updated_at, created_at) FROM people # => ['0', '27761', '173']
scope(name, body, &block)
class Book < ActiveRecord::Base scope :gihyo, -> { where(publish: '技術評論社') } scope :newer, -> { order(published: :desc) } scope :top10, -> { newer.limit(10) } # 既存のスコープ(ここではnewer)の利用可能 scope :whats_new, ->(pub) { where(publish: pub).order(published: :desc).limit(5) }
default_scope(scope = nil)
unscope
メソッドでクリアできる。
# TODO
count(column_name = nil)
レコードが存在しない場合、0
を返す。
引数にカラム名が指定された場合、そのカラムがNULL
でないレコードの件数を返す。
average(column_name)
レコードが存在しない場合、nil
を返す。
avgs = Book.group(:publish).average(:price) # SELECT AVG("books"."price") AS average_price, publish AS publish FROM "books" GROUP BY "books"."publish" # Book.select('publish, AVG(price) AS avg_price').group(:publish)と同等 avgs.each do |publish, avg| puts avg.to_s + '|' + publish end # 2625.0|ソシム # 2996.0|技術評論社 # 2152.5|日経BP社 # 3150.0|秀和システム # 3283.0|翔泳社
minimum(column_name)
レコードが存在しない場合、nil
を返す。
maximum(column_name)
レコードが存在しない場合、nil
を返す。
sum(column_name = nil, &block)
レコードが存在しない場合、0
を返す
ids()
Person.ids # SELECT people.id FROM people Person.joins(:companies).ids # SELECT people.id FROM people INNER JOIN companies ON companies.person_id = people.id
ActiveRecord::Base.connection.select_rows(sql, name = nil, binds = [])
引数に渡したクエリを実行して結果を配列で返す。
まず業務では使わないと思うが試験対策として。
ActiveRecord::Base.connection.select_rows('select id, title from books') # select id, title from books # => [[1, "AndroidエンジニアのためのモダンJava"], # [2, "JavaScriptライブラリ実践活用"], # [3, "Ruby on Rails 4ポケットリファレンス"], # [4, "書き込み式SQLのドリル"], # [5, "はじめてのAndroidアプリ開発"], # [6, "10日でおぼえるPHP入門教室"], # [7, "アプリを作ろう!HTML5入門"], # [8, "HTML5 開発ポケットリファレンス"], # [9, "独習Java サーバサイド編"], # [10, "Flash CSで学ぶ iPhone実践プログラミング"]]
select_values(arel, name = nil, binds = [])
引数に渡したクエリを実行して、最初のカラムの値を配列で返す。
まず業務では使わないと思うがs(ry
ActiveRecord::Base.connection.select_values('select id, title from books') # select id, title from books # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
ActiveRecord::Relation
update_all(updates)
destroy(id)
Book.destroy 2 # Book Load (0.2ms) SELECT "books".* FROM "books" WHERE "books"."id" = ? LIMIT 1 [["id", 2]] # (0.1ms) SAVEPOINT active_record_1 # SQL (0.9ms) DELETE FROM "authors_books" WHERE "authors_books"."book_id" = ? [["book_id", 2]] # SQL (0.6ms) DELETE FROM "books" WHERE "books"."id" = ? [["id", 2]] # (0.1ms) RELEASE SAVEPOINT active_record_1
destroy()
book = Book.find 2 book.destroy
delete(id_or_array)
DELETE文の発行。
Modelで定義したassociationは考慮されない。
Book.delete 1 # DELETE FROM "books" WHERE "books"."id" = ? [["id", 1]]
delete()
book = Book.find 2 book.delete
destroy_all(conditions = nil)
Person.where(age: 0..18).destroy_all
transaction
transaction(requires_new: nil, isolation: nil, joinable: true)
isolation levels
- :read_uncommitted
- :read_committed
- :repeatable_read
- :serializable
Optimistic Locking (楽観的ロック)
Optimistic Lockingを実装することで、競合を回避することができる。
以下の手順で実装すると競合を起こした際にActiveRecord::StaleObjectError
が発生するようになる
- 同時実行制御したいテーブルに
lock_version
カラムを追加する。なお、型はinteger
で、デフォルト値は0
ActiveRecord::Base.lock_optimistically
をtrue
にする (デフォルトはtrueとなっているが)- HTMLのフォームに
lock_version
パラメータを仕込む - strong parameterに
lock_version
を追加
例)
class Item < ActiveRecord::Migration def change create_table :itmes do |t| t.string :name t.integer :lock_version, default: 0 t.time_stamps end end end
なお、楽観的ロック用のカラム名はlocking_column=
メソッドで変更できる
例)ロック用カラム名をlock_itmeに変更
class Item < ActiveRecord::Migration locking_column = :lock_item
Validation
common options
- on
- if
- unless
- allow_nil
- allow_blank
- strict
- message
presence
値が存在しているかどうか。
判断基準はObject#blank?
による。
validates :name, presence: true
absence
上記precence
の逆
length
options
- minimum
- maximum
- is
- within
- in
- too_long
- too_short
- allow_nil
- allow_blank
- wrong_length
validates :first_name, length: { maximum: 30 } validates :last_name, length: { maximum: 30, message: "less than 30 if you don't mind" } validates :fax, length: { in: 7..32, allow_nil: true } validates :phone, length: { in: 7..32, allow_blank: true } validates :user_name, length: { within: 6..20, too_long: 'pick a shorter name', too_short: 'pick a longer name' } validates :zip_code, length: { minimum: 5, too_short: 'please enter at least 5 characters' } validates :smurf_leader, length: { is: 4, message: "papa is spelled with 4 characters... don't play me." }
numericality
options
- only_integer
- allow_nil
- greater_than
- greater_than_or_equal_to
- equal_to
- less_than
- less_than_or_equal_to
- other_than
- odd
- even
format
options
- with
- without
- multiline
validates :phone_number, format: { with: /\A\d{2,3}-\d{4}-\d{4}\z/ }
uniqueness
options
- scope
- conditions
- case_sensitive
- allow_nil
- allow_blank
- if
- unless
acceptance
options
- accept
confirmation
options
- case_sensitive
inclusion
options
- in
exclusion
options
- in
Association
DB
設定
config/database.yml
# SQLite version 3.x # gem install sqlite3 # # Ensure the SQLite 3 gem is defined in your Gemfile # gem 'sqlite3' # default: &default adapter: sqlite3 pool: 5 timeout: 5000 development: <<: *default database: db/development.sqlite3 # Warning: The database defined as "test" will be erased and # re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: <<: *default database: db/test.sqlite3 production: <<: *default database: db/production.sqlite3
database.ymlのパラメータ
パラメータ名 | 概要 |
---|---|
adapter | 接続するデータベースの種類(sqlite3, mysql2, postgresqlなど) |
database | データベース名(SQLiteの場合データベースファイルのパス) |
host | ホスト名 / IPアドレス |
port | ポート番号 |
pool | プール数 |
timeout | タイムアウト時間 |
encoding | 文字コード |
username | ユーザ名 |
password | パスワード |
socket | ソケット(/tmp/mysql.sockなど) |
マイグレーションによるテーブル作成
- マイグレーションファイルは
rails g migration
もしくはrails g model
コマンドで生成される - ファイル名の規約は
{UTCタイムスタンプ}_{マイグレーション名}.rb
- マイグレーション名とファイル名が一致していないとエラーが発生する
- マイグレーションクラスは
ActiveRecord::Migration
を継承させる
例)20130914060842_create_books.rb
$ rails g model book isbn:string title:string price:integer publish:string published:date cd:boolean
# ファイル名が20130914060842_create_books.rbの場合、 # クラス名はCreateBooksでなければならない。 class CreateBooks < ActiveRecord::Migration def change create_table :books do |t| t.string :isbn t.string :title t.integer :price t.string :publish t.date :published t.boolean :cd t.timestamps end end end
rails g migration のマイグレーション名
マイグレーション名 | 概要 | 例 |
---|---|---|
Create{TableName} | テーブルの作成 | rails g migration CreateUsers name:string |
Add{ColumnName}To{TableName} | カラムの追加 | |
Remove{ColumnName}From{TableName} | カラムの削除 | |
CreateJoinTable{Table1Table2} | habtm用テーブルの作成 |
Railsが自動生成するカラム
カラム名 | 概要 |
---|---|
id | 主キー(連番) |
created_at | レコードの新規作成日時(Active Recordが自動セット) |
updated_at | レコードの更新日時(Active Recordが自動セット) |
フィクスチャによるテストデータの作成
$ rake db:fixtures:load FIXTURES=items
ActiveRecordのコールバック
作成時 | 更新時 | 削除時 |
---|---|---|
before_validation | before_validation | before_destroy |
after_validation | after_validation | around_destroy |
before_save | before_save | after_destroy |
around_save | around_save | |
before_create | before_update | |
around_create | around_update | |
before_create | after_update | |
after_save | after_save |
* 上から順に呼ばれる
app/models/item.rb
class Item < ActiveRecord::Base before_create { logger.debug 'called before_create' } after_create { logger.debug 'called after_create' } end
データ作成処理
require 'item' item = Item.new item.name = 'fuga' item.price = 200 item.save
log
(0.1ms) SAVEPOINT active_record_1 called before_create SQL (0.9ms) INSERT INTO "items" ("name", "price", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["name", "fuga"], ["price", 200], ["created_at", "2016-06-09 19:59:15.390360"], ["updated_at", "2016-06-09 19:59:15.390360"]] called after_create (0.1ms) RELEASE SAVEPOINT active_record_1
初期データの投入
db/seeds.rb
# This file should contain all the record creation needed to seed the database with its default values. # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). # # Examples: # # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) # Mayor.create(name: 'Emanuel', city: cities.first) Item.create(name: 'hoge', price: 100)
$ rake db:seed
sqlite> select * from items; 1|hoge|100|2016-06-09 19:57:38.782345|2016-06-09 19:57:38.782345
データベースを設定する
rake db:setupタスクは、データベースの作成、スキーマの読み込み、シードデータを使用したデータベースの初期化を実行します。
db:seedはテーブルのクリアは行われないため、既存のデータと一意性制約で引っかかることがある。
$ rake db:seed rake aborted! ActiveRecord::RecordNotUnique: SQLite3::ConstraintException: UNIQUE constraint failed: items.name: INSERT INTO "items" ("name", "price", "created_at", "updated_at") VALUES (?, ?, ?, ?) /Users/makoto/Documents/src/Rails/TestApp/db/seeds.rb:9:in `<top (required)>' SQLite3::ConstraintException: UNIQUE constraint failed: items.name /Users/makoto/Documents/src/Rails/TestApp/db/seeds.rb:9:in `<top (required)>' Tasks: TOP => db:seed (See full trace by running task with --trace)
その際は、db:setupを行う。
$ rake db:setup db/development.sqlite3 already exists db/test.sqlite3 already exists -- create_table("items", {:force=>:cascade}) -> 0.0067s -- add_index("items", ["name"], {:name=>"index_items_on_name", :unique=>true}) -> 0.0241s -- initialize_schema_migrations_table() -> 0.0083s -- create_table("items", {:force=>:cascade}) -> 0.0115s -- add_index("items", ["name"], {:name=>"index_items_on_name", :unique=>true}) -> 0.0022s -- initialize_schema_migrations_table() -> 0.0003s
データベースをリセットする
rake db:resetタスクは、データベースをdropして再度設定します。このタスクは、rake db:drop db:setupと同等です。
バリューオブジェクト
3. RoutingとController
リソースフルのルーティング
resourcesメソッドによるルーティング設定
resources :users
$ rake routes Prefix Verb URI Pattern Controller#Action users GET /users(.:format) users#index POST /users(.:format) users#create new_user GET /users/new(.:format) users#new edit_user GET /users/:id/edit(.:format) users#edit user GET /users/:id(.:format) users#show PATCH /users/:id(.:format) users#update PUT /users/:id(.:format) users#update DELETE /users/:id(.:format) users#destroy
resourceメソッドによるルーティング設定
resource :config
$ rake routes Prefix Verb URI Pattern Controller#Action config POST /config(.:format) configs#create new_config GET /config/new(.:format) configs#new edit_config GET /config/edit(.:format) configs#edit GET /config(.:format) configs#show PATCH /config(.:format) configs#update PUT /config(.:format) configs#update DELETE /config(.:format) configs#destroy
only / except
デフォルトで生成されるアクションの一部を無効化する。
必要のないルーティングを残すとパフォーマンスが低下するため、必要ないものが分かっていれば設定すること。
# show, destroyアクション以外を生成する resources :users, except: [ :show, :destroy ]
# index, new, createアクションだけを生成する resources :users, only: [ :index, :new, :create]
constraints
ルートパラメータに制限を設ける。
# idに指定できるパラメータを2桁の数字に制限する。 resources :users, constraints: { id: /[0-9]{1,2}/ }
format
true
にするとフォーマットの指定が必須となる- 指定しないとActionController::RoutingErrorが発生する
resources :users, format: true
Prefix Verb URI Pattern Controller#Action users GET /users.:format users#index {:format=>/.+/} POST /users.:format users#create {:format=>/.+/} new_user GET /users/new.:format users#new {:format=>/.+/} edit_user GET /users/:id/edit.:format users#edit {:format=>/.+/} user GET /users/:id.:format users#show {:format=>/.+/} PATCH /users/:id.:format users#update {:format=>/.+/} PUT /users/:id.:format users#update {:format=>/.+/} DELETE /users/:id.:format users#destroy {:format=>/.+/}
false
にするとフォーマットができなくなる- 指定するとActionController::RoutingErrorが発生する
resources :users, format: false
Prefix Verb URI Pattern Controller#Action users GET /users users#index POST /users users#create new_user GET /users/new users#new edit_user GET /users/:id/edit users#edit user GET /users/:id users#show PATCH /users/:id users#update PUT /users/:id users#update DELETE /users/:id users#destroy
controllers
デフォルトと異なるコントローラを指定する。
# デフォルトの場合、UsersControllerとマッピングされるが、 # 下記の場合、MembersControllerとマッピングされる。 resources :users, controllers: :members
$ rake routes Prefix Verb URI Pattern Controller#Action users GET /users(.:format) users#index {:controllers=>:members} POST /users(.:format) users#create {:controllers=>:members} new_user GET /users/new(.:format) users#new {:controllers=>:members} edit_user GET /users/:id/edit(.:format) users#edit {:controllers=>:members} user GET /users/:id(.:format) users#show {:controllers=>:members} PATCH /users/:id(.:format) users#update {:controllers=>:members} PUT /users/:id(.:format) users#update {:controllers=>:members} DELETE /users/:id(.:format) users#destroy {:controllers=>:members}
as
デフォルトと異なるUrlヘルパーを生成する。
# デフォルトの場合、users_pathやuser_pathが生成されるが、 # 下記の場合、members_pathやmember_pathが生成される。 resources :users, as: :members
$ rake routes Prefix Verb URI Pattern Controller#Action members GET /users(.:format) users#index POST /users(.:format) users#create new_member GET /users/new(.:format) users#new edit_member GET /users/:id/edit(.:format) users#edit member GET /users/:id(.:format) users#show PATCH /users/:id(.:format) users#update PUT /users/:id(.:format) users#update DELETE /users/:id(.:format) users#destroy
collection / member ブロック
任意のアクションを追加する。
resources :reviews do collection do get :unapproval end member do get :draft end end
$ rake routes Prefix Verb URI Pattern Controller#Action unapproval_reviews GET /reviews/unapproval(.:format) reviews#unapproval draft_review GET /reviews/:id/draft(.:format) reviews#draft reviews GET /reviews(.:format) reviews#index POST /reviews(.:format) reviews#create new_review GET /reviews/new(.:format) reviews#new edit_review GET /reviews/:id/edit(.:format) reviews#edit review GET /reviews/:id(.:format) reviews#show PATCH /reviews/:id(.:format) reviews#update PUT /reviews/:id(.:format) reviews#update DELETE /reviews/:id(.:format) reviews#destroy
なお、ブロック配下のアクションが1つの場合、onパラメータを使って簡易に記述できる
resources :reviews do get :unapproval, on: :collection get :draft, on: :member end
shallow
namespace
コントローラをモジュール分割する
namespace :admin do resources :book end
admin_book_index GET /admin/book(.:format) admin/book#index POST /admin/book(.:format) admin/book#create new_admin_book GET /admin/book/new(.:format) admin/book#new edit_admin_book GET /admin/book/:id/edit(.:format) admin/book#edit admin_book GET /admin/book/:id(.:format) admin/book#show PATCH /admin/book/:id(.:format) admin/book#update PUT /admin/book/:id(.:format) admin/book#update DELETE /admin/book/:id(.:format) admin/book#destroy
scope
コントローラをモジュール分割する(URLに影響しない)
scope module: :admin do resources :book end
Prefix Verb URI Pattern Controller#Action book_index GET /book(.:format) admin/book#index POST /book(.:format) admin/book#create new_book GET /book/new(.:format) admin/book#new edit_book GET /book/:id/edit(.:format) admin/book#edit book GET /book/:id(.:format) admin/book#show PATCH /book/:id(.:format) admin/book#update PUT /book/:id(.:format) admin/book#update DELETE /book/:id(.:format) admin/book#destroy
URLにプレフィクスをつける
scope :admin do resources :book end
Prefix Verb URI Pattern Controller#Action book_index GET /admin/book(.:format) book#index POST /admin/book(.:format) book#create new_book GET /admin/book/new(.:format) book#new edit_book GET /admin/book/:id/edit(.:format) book#edit book GET /admin/book/:id(.:format) book#show PATCH /admin/book/:id(.:format) book#update PUT /admin/book/:id(.:format) book#update DELETE /admin/book/:id(.:format) book#destroy
concern
ルート定義の再利用。
concern :addtional do get :unapproval, on: :collection get :darft, on: :member end resources :reviews, concerns: :addtional resources :users, concerns: :addtional
$ rake routes Prefix Verb URI Pattern Controller#Action unapproval_reviews GET /reviews/unapproval(.:format) reviews#unapproval darft_review GET /reviews/:id/darft(.:format) reviews#darft reviews GET /reviews(.:format) reviews#index POST /reviews(.:format) reviews#create new_review GET /reviews/new(.:format) reviews#new edit_review GET /reviews/:id/edit(.:format) reviews#edit review GET /reviews/:id(.:format) reviews#show PATCH /reviews/:id(.:format) reviews#update PUT /reviews/:id(.:format) reviews#update DELETE /reviews/:id(.:format) reviews#destroy unapproval_users GET /users/unapproval(.:format) users#unapproval darft_user GET /users/:id/darft(.:format) users#darft users GET /users(.:format) users#index POST /users(.:format) users#create new_user GET /users/new(.:format) users#new edit_user GET /users/:id/edit(.:format) users#edit user GET /users/:id(.:format) users#show PATCH /users/:id(.:format) users#update PUT /users/:id(.:format) users#update DELETE /users/:id(.:format) users#destroy
ノンリソースフル
matchメソッドの引数のパターン
# 以下3つは同じルーティングになる match 'photos/:id' => 'photos#show', via: :get match 'photos/:id', to: 'photos#show', via: :get match 'photos/:id', controller: 'photos', action: 'show', via: :get # また、viaオプションの代わりにget(post, put, patch, delete)メソッドに置き換えることができる get 'photos/:id' => 'photos#show' get 'photos/:id', to: 'photos#show' get 'photos/:id', controller: 'photos', action: 'show'
$ rake routes Prefix Verb URI Pattern Controller#Action GET /photos/:id(.:format) photos#show
URLパラメータ
# :controllerと:actionはそれぞれコントローラ名、アクション名とマッピングされる match ':controller/:action/:id', via: [:get, :post]
アクション、コントローラの指定の省略
# URIパターンが「/action/method」の形であれば「=> 'action#method'」を省略できる get '/home/about'
$ rake routes Prefix Verb URI Pattern Controller#Action home_about GET /home/about(.:format) home#about
ワイルドカード
# urlのパターンにはワイルドカード指定ができる get 'songs/*category/:title', to: 'songs#show' # 'songs/rock/classic/stairway-to-heaven' sets # params[:category] = 'rock/classic' # params[:title] = 'stairway-to-heaven'
$ rake routes Prefix Verb URI Pattern Controller#Action GET /songs/*category/:title(.:format) songs#show
rootメソッド
root to: 'pages#main' # toは省略可能 # root 'pages#main'
redirectメソッド
redirct
メソッドを利用すると指定したURLへリダイレクトさせることができる
get 'home/about' => redirect('/home2/about/')
Prefix Verb URI Pattern Controller#Action home_about GET /home/about(.:format) redirect(301, /home2/about/)
# rootメソッドと組み合わせる場合、toの省略はできない root to: redirect('/admin/uers')
Prefix Verb URI Pattern Controller#Action root GET / redirect(301, /admin/uers)
その他
URLに日本語を含めることができる
get 'ほげ/index' => 'hoge#index'
Prefix Verb URI Pattern Controller#Action GET /%E3%81%BB%E3%81%92/index(.:format) hoge#index
ルーティングの優先順位
- 上から順に評価される
- よって、スコープの広いもの(rootとか)は後のほうに定義すべき
# リソースフル resources :users # 「/about」でアクセスするとHomeController#aboutが呼ばれる get '/about' => 'home#about' # URIパターンが「/action/method」の形であれば「=> 'action#method'」を省略できる get '/home/about' # 「/hoge」でアクセスするとPagesController#hogeが呼ばれる get '/:action', controller: :pages # matchメソッド。「/hoge」でアクセスすると、HogeController#indexが呼ばれる match '/hoge', to: 'hoge#index' , via: :get # rootメソッドによるルーティング root 'home#index'
URLやパスに関するメソッド
resources :users root 'users#index'
xxx_url
root_url # => "http://localhost:3000/" users_url # => "http://localhost:3000/users" users_url :json # => "http://localhost:3000/users.json" user_url 1 # => "http://localhost:3000/users/1" user_url 1, :json # => "http://localhost:3000/users/1.json" # パラメータが指定されているルーティングに対し、パラメータを渡さないとActionController::UrlGenerationErrorが発生する user_url # ActionController::UrlGenerationError: No route matches {:action=>"show", :controller=>"users"} missing required keys: [:id]
xxx_path
root_path # => "/" users_path # => "/users" edit_user_path 1 #=> "/users/1/edit" edit_user_path # ActionController::UrlGenerationError: No route matches {:action=>"edit", :controller=>"users"} missing required keys: [:id]
url_for(options = nil)
options
- only_path - If true, the relative url is returned. Defaults to false.
- protocol - The protocol to connect to. Defaults to 'http'.
- host - Specifies the host the link should be targeted at. If :only_path is false, this option must be provided either explicitly, or via default_url_options.
- subdomain - Specifies the subdomain of the link, using the tld_length to split the subdomain from the host. If false, removes all subdomains from the host part of the link.
- domain - Specifies the domain of the link, using the tld_length to split the domain from the host.
- tld_length - Number of labels the TLD id composed of, only used if :subdomain or :domain are supplied. Defaults to ActionDispatch::Http::URL.tld_length, which in turn defaults to 1.
- port - Optionally specify the port to connect to.
- anchor - An anchor name to be appended to the path.
- trailing_slash - If true, adds a trailing slash, as in “/archive/2009/”
- script_name - Specifies application path relative to domain root. If provided, prepends application path.
url_for controller: 'tasks', action: 'testing', host: 'somehost.org', port: '8080' # => 'http://somehost.org:8080/tasks/testing' url_for controller: 'tasks', action: 'testing', host: 'somehost.org', anchor: 'ok', only_path: true # => '/tasks/testing#ok' url_for controller: 'tasks', action: 'testing', trailing_slash: true # => 'http://somehost.org/tasks/testing/' url_for controller: 'tasks', action: 'testing', host: 'somehost.org', number: '33' # => 'http://somehost.org/tasks/testing?number=33' url_for controller: 'tasks', action: 'testing', host: 'somehost.org', script_name: "/myapp" # => 'http://somehost.org/myapp/tasks/testing' url_for controller: 'tasks', action: 'testing', host: 'somehost.org', script_name: "/myapp", only_path: true # => '/myapp/tasks/testing'
url_for(only_path: true) # => '/users/1' url_for(only_path: true, action: 'edit') # => '/users/1/edit' url_for(only_path: true, action: 'edit', id: 2) # => '/users/2/edit'
scaffold
$ rails g scaffold Note title:string content:text Running via Spring preloader in process 84352 invoke active_record create db/migrate/20160610073826_create_notes.rb create app/models/note.rb invoke test_unit create test/models/note_test.rb create test/fixtures/notes.yml invoke resource_route route resources :notes invoke scaffold_controller create app/controllers/notes_controller.rb invoke erb create app/views/notes create app/views/notes/index.html.erb create app/views/notes/edit.html.erb create app/views/notes/show.html.erb create app/views/notes/new.html.erb create app/views/notes/_form.html.erb invoke test_unit create test/controllers/notes_controller_test.rb invoke helper create app/helpers/notes_helper.rb invoke test_unit invoke jbuilder create app/views/notes/index.json.jbuilder create app/views/notes/show.json.jbuilder invoke assets invoke coffee create app/assets/javascripts/notes.coffee invoke scss create app/assets/stylesheets/notes.scss invoke scss create app/assets/stylesheets/scaffolds.scss $ $ $ $ git status On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: config/routes.rb Untracked files: (use "git add <file>..." to include in what will be committed) app/assets/javascripts/notes.coffee app/assets/stylesheets/notes.scss app/assets/stylesheets/scaffolds.scss app/controllers/notes_controller.rb app/helpers/notes_helper.rb app/models/note.rb app/views/notes/ db/migrate/ test/controllers/notes_controller_test.rb test/fixtures/notes.yml test/models/note_test.rb
コントローラ
CoC (Convention over Configuration)
種類 | 概要 | 例 |
---|---|---|
コントローラクラス | キャメル(先頭大文字) | HelloController |
コントローラクラス(ファイル) | スネークケース(小文字) | hello_controller.rb |
ヘルパーファイル名 | コントローラ名に接尾辞「_helper.rb」 | hello_helper.rb |
テストスクリプト名 | コントローラ名に接尾辞「_controller_test.rb」 | hello_controller_test.rb |
rails generate controller
$ rails g controller -h Running via Spring preloader in process 14930 Usage: rails generate controller NAME [action action] [options] Options: [--skip-namespace], [--no-skip-namespace] # Skip namespace (affects only isolated applications) [--skip-routes], [--no-skip-routes] # Don't add routes to config/routes.rb. -e, [--template-engine=NAME] # Template engine to be invoked # Default: erb -t, [--test-framework=NAME] # Test framework to be invoked # Default: test_unit [--helper] # Indicates when to generate helper # Default: true [--assets] # Indicates when to generate assets # Default: true Runtime options: -f, [--force] # Overwrite files that already exist -p, [--pretend], [--no-pretend] # Run but do not make any changes -q, [--quiet], [--no-quiet] # Suppress status output -s, [--skip], [--no-skip] # Skip files that already exist Description: Stubs out a new controller and its views. Pass the controller name, either CamelCased or under_scored, and a list of views as arguments. To create a controller within a module, specify the controller name as a path like 'parent_module/controller_name'. This generates a controller class in app/controllers and invokes helper, template engine, assets, and test framework generators. Example: `rails generate controller CreditCards open debit credit close` CreditCards controller with URLs like /credit_cards/debit. Controller: app/controllers/credit_cards_controller.rb Test: test/controllers/credit_cards_controller_test.rb Views: app/views/credit_cards/debit.html.erb [...] Helper: app/helpers/credit_cards_helper.rb
redirect_to(options = {}, response_status = {})
redirect_to
メソッドに渡せる引数やオプションはurl_for
メソッドと同じ
# URL redirect_to 'http://example.com' # 同一コントローラ内のアクション redirect_to action: :index # 他コントローラのアクション redirect_to controller: :user, action: :index # viewヘルパー users_path # 前の画面 redirect_to :back
render
options
- action: 違うアクションに対応するテンプレートファイルを指定する
- template: 異なるコントローラのテンプレートそ指定する
- partial: 部分テンプレートを出力する
- file: 絶対パスでテンプレートファイルを指定する
- text: 値をそのまま出力する
- plain: 値をそのまま出力する。textとの違いはcontent-typeが
text/plain
となること - html: htmlエスケープされて出力される
- inline: erbと解釈して
- body: TODO
class BooksController < ApplicationController def create render action: :index # render :index # actionは省略可能 render template: 'others/index' # render 'others/index' # 指定した値の途中に「/」がある場合、templateは省略できる render file: '/hoge/index.html.erb' # render '/hoge/index.html.erb' # 指定した値が「/」で始まっている場合、fileは省略できる
respond_to
respond_to do |format| format.xxx { #something to process } end
指定されたフォーマットの処理がない場合、ActionController::UnKnownFormat
が発生する
head
def ok head :ok end def created head :created end def moved head :moved_permanently end def found head :found end def see_other head :see_other end def unauthorized head :unauthorized end def forbidden head :forbidden end def not_found head :not_found end def method_not_allowed head :method_not_allowed end def internal_server_error head :internal_server_error end
send_data
optinos
- filename
- type
- disposition
- status
send_file
options
- filename
- type
- disposition
- status
- url_based_filename
認証
authenticate_or_request_with_http_basic(realm = "Application", message = nil, &login_procedure)
class ApplicationController < ActionController::Base before_action :auth def auth authenticate_or_request_with_http_basic do |user, pass| user == 'name' && pass == 'pass' end end
http_basic_authenticate_with(options = {})
class ApplicationController < ActionController::Base http_basic_authenticate_with name: 'name', password: 'pass'
logger
log level
config.log_level
logging フィルタ
config/initializers/filter_parameter_logging.rb
Rails.application.config.filter_parameters += [:password, :credit]
正規表現も使える。
Rails.application.config.filter_parameters += [/credit/]
ステート管理
Cookie
options
- value
- path
- domain
- tld_length
- expires
- secure
- httponly
# 設定 cookies[:email] = { value: 'makoto@example.com', expires: 1.days.from_now, # 有効期限 domain: 'example.com', # Cookieが有効なドメイン path: '/~www', # Cookieが有効なパス httponly: true, # trueにするとjavascriptから操作できなくなる (default: false) secure: true # trueにするとssl通信時のみCookieを利用する (default: false) } # 取得 cookies[:email] # => makoto@example.com # 削除 cookies.delete :email # domain、pathオプションを設定している場合は、明示的に指定しないと削除できない cookies.delete :email, path: '/~www'
signed
ユーザによるCookieの書き換えを無効にする。
secrets.secret_key_base
を設定しておく必要がある。
encrypted
暗号化する。
secrets.secret_key_base
を設定しておく必要がある。
cookies.encrypted[:discount] = 45
permanent
有効期限が20年のCookieを生成する。
また、expiresオプションを設定してもpermanent
が優先される。
cookies.permanent[:login] = "XJ-122"
なお、上記メソッドは複数合わせて利用可能
cookies.permanent.signed[:login] = "XJ-122"
Session
# 設定 session[:email] = test@example.com # 取得 @email = session[:email] # 特定の値の削除 session[:email] = nil # 全て削除 reset_session
設定
セッションに関する設定を変更するにはconfig/initializers/session_store.rb
中のconfig.session_store
の値を変更する。
第一引数にはデータストアの種類を、第二引数にはハッシュで動作パラメータを渡す。
config/initializers/session_store.rb
Rails.application.config.session_store :cookie_store, key: '_tmp_session'
データストアの種類
セッションには以下の通り、保存先が3つ設定可能
- クッキーストア
- キャッシュストア
- アクティブレコードストア(DB)
保存場所 | 設定値 |
---|---|
クッキーストア | :cookie_store |
キャッシュストア | :cache_store |
アクティブレコードストア | :active_record_store |
セッションの無効化 | :disabled |
動作パラメータ
データストアの種類によって動作パラメータは変わる。
以下は共通のパラメータ。
パラメータ | 概要 | default |
---|---|---|
key | セッションキーを格納するクッキー名 | _session_id |
domain | セッションクッキーの有効なドメイン | nil |
path | セッションクッキーが有効なパス | / |
expire_after | セッションの有効期間 | nil (ブラウザを閉じるまで) |
secure | :SSL通信の場合のみクッキーを送信するか | false |
httponly | HTTPクッキーを有効にするか | true |
flash
notice
alert
flash
コントローラでの設定
flash[:msg] = 'hogehoge'
erbでの参照
<%= flash[:msg] %>
now
現在のアクションのみで有効。
flash.now[:msg] = 'hogeeeeee'
keep
次のアクションまで有効。
discard
flashの破棄。
フィルタ
共通オプション
- only
- except
before_action
after_action
around_action
around_action :around_logger, only: [:index, :new] # around_action :around_logger, only: :index # around_action :around_logger, except: :index private def around_logger logger.debug 'start aciton' yield # アクションの実行 logger.debug 'end action' end
skip_xxxx_action
継承したフィルタを除外する。
例)TopControllerのindexアクションだけ、before_action :authenticate_user!
をスキップする
application_controller.rb
class ApplicationController < ActionController::Base before_action :authenticate_user!
top_controller.rb
class TopController < ApplicationController skip_before_action :authenticate_user!, only: :index
ApplicationControllerについて
ApplicationControllerは全てのControllerの基底クラスになるため、Controllerで共通する処理を定義するのに適している。
以下よくある共通処理
- ログイン認証などのフィルタ
- 共通的な例外処理
protect_from_forgery
によるCSRF対策add_flash_types
による独自のフラッシュメッセージの定義
例外処理
rescue_from
メソッドを利用することで、例外発生時の処理を定義できる。
ちなみに例外が補足されなかった場合は、発生した例外に応じてHTTPステータスが割り当てられ、それに応じたエラーページが表示される。
例えば、RoutingError
が発生すると404 Not Found
がステータスとして割り振られ、404.html
が表示される。
なお、このエラーページが表示される挙動はconfig.consider_all_requests_local
がfalse
の場合のみで、development環境ではデフォルトでtrue
となっている。
rescue_from(*klasses, with: nil, &block)
# ブロックで処理を記述 rescue_from MyAppError::Base do |exception| render xml: exception, status: 500 end # メソッド呼び出し rescure_from MyAppError::Base, with: :id_invalid private def id_invalid # someting to process end
4. View
コメント
<%# コメント %> <%# 複数行 コメントもOK! %> <% =begin %> この間は全てコメントとなる *! "=begin"や"=end"は行頭にないと無効 <% =end %> <% if false %> この間は全てコメントとなる(処理されない) <% end %>
FormHelper
form_tag(url_for_options = {}, options = {}, &block)
例)
form_tag('/posts/1', method: :put) # => # <form action="/posts/1" accept-charset="UTF-8" method="post"> # <input name="utf8" type="hidden" value="✓"> # <input type="hidden" name="_method" value="put"> # <input type="hidden" name="authenticity_token" value="jZygzwz35Uvy6+BcusAn1VTokEZGfsZMa4KEJfi3fYIKhtgh/eztG9Yk+/+oPUOuhsJJNsHBbgPd3lMnyLcAFw=="> # </form>
* 第一引数のURLにハッシュを渡す場合、url_forに準じた書式で値を渡すことでURLが生成される
例)
form_tag({controller: "people", action: "search"}, method: "get", class: "nifty_form") # => # <form class="nifty_form" action="/people/search" accept-charset="UTF-8" method="get"> # <input name="utf8" type="hidden" value="✓"> # </form>
* 第一引数のハッシュと第二引数のハッシュを区別するため、第一引数の{}は省略できないことに注意
text_field_tag(name, value = nil, options = {})
text_field_tag 'name' # => <input id="name" name="name" type="text" /> text_field_tag 'query', 'Enter your search query here' # => <input id="query" name="query" type="text" value="Enter your search query here" /> text_field_tag 'search', nil, placeholder: 'Enter search term...' # => <input id="search" name="search" placeholder="Enter search term..." type="text" /> text_field_tag 'request', nil, class: 'special_input' # => <input class="special_input" id="request" name="request" type="text" /> text_field_tag 'address', '', size: 75 # => <input id="address" name="address" size="75" type="text" value="" /> text_field_tag 'zip', nil, maxlength: 5 # => <input id="zip" maxlength="5" name="zip" type="text" /> text_field_tag 'payment_amount', '$0.00', disabled: true # => <input disabled="disabled" id="payment_amount" name="payment_amount" type="text" value="$0.00" /> text_field_tag 'ip', '0.0.0.0', maxlength: 15, size: 20, class: "ip-input" # => <input class="ip-input" id="ip" maxlength="15" name="ip" size="20" type="text" value="0.0.0.0" />
select_tag(name, option_tags = nil, options = {})
options
- multiple
- disabled
- include_blank
- prompt
- その他HTML属性
select_tag "people", options_from_collection_for_select(@people, "id", "name") # <select id="people" name="people"><option value="1">David</option></select> select_tag "people", options_from_collection_for_select(@people, "id", "name", "1") # <select id="people" name="people"><option value="1" selected="selected">David</option></select> select_tag "people", raw("<option>David</option>") # => <select id="people" name="people"><option>David</option></select> select_tag "count", raw("<option>1</option><option>2</option><option>3</option><option>4</option>") # => <select id="count" name="count"><option>1</option><option>2</option> # <option>3</option><option>4</option></select> select_tag "colors", raw("<option>Red</option><option>Green</option><option>Blue</option>"), multiple: true # => <select id="colors" multiple="multiple" name="colors[]"><option>Red</option> # <option>Green</option><option>Blue</option></select> select_tag "locations", raw("<option>Home</option><option selected='selected'>Work</option><option>Out</option>") # => <select id="locations" name="locations"><option>Home</option><option selected='selected'>Work</option> # <option>Out</option></select> select_tag "access", raw("<option>Read</option><option>Write</option>"), multiple: true, class: 'form_input', id: 'unique_id' # => <select class="form_input" id="unique_id" multiple="multiple" name="access[]"><option>Read</option> # <option>Write</option></select> select_tag "people", options_from_collection_for_select(@people, "id", "name"), include_blank: true # => <select id="people" name="people"><option value=""></option><option value="1">David</option></select> select_tag "people", options_from_collection_for_select(@people, "id", "name"), include_blank: "All" # => <select id="people" name="people"><option value="">All</option><option value="1">David</option></select> select_tag "people", options_from_collection_for_select(@people, "id", "name"), prompt: "Select something" # => <select id="people" name="people"><option value="">Select something</option><option value="1">David</option></select> select_tag "destination", raw("<option>NYC</option><option>Paris</option><option>Rome</option>"), disabled: true # => <select disabled="disabled" id="destination" name="destination"><option>NYC</option> # <option>Paris</option><option>Rome</option></select> select_tag "credit_card", options_for_select([ "VISA", "MasterCard" ], "MasterCard") # => <select id="credit_card" name="credit_card"><option>VISA</option> # <option selected="selected">MasterCard</option></select>
<%= select_tag 'publish', raw('<option value="1">技術評論社</option><option value="2">翔泳社</option><option value="3">マイナビ</option>') %>
<%= select_tag 'publish', options_for_select( { '技術評論社' => 1, '翔泳社' => 2, 'マイナビ' => 3 }, 2) %>
options_from_collection_for_select(collection, value_method, text_method, selected = nil)
options_from_collection_for_select(@people, 'id', 'name') # => <option value="#{person.id}">#{person.name}</option>
select_tag
との併用例
select_tag 'person', options_from_collection_for_select(@people, 'id', 'name')
options_for_select(container, selected = nil)
options_for_select([["Dollar", "$"], ["Kroner", "DKK"]]) # => <option value="$">Dollar</option> # => <option value="DKK">Kroner</option> options_for_select([ "VISA", "MasterCard" ], "MasterCard") # => <option value="VISA">VISA</option> # => <option selected="selected" value="MasterCard">MasterCard</option> options_for_select({ "Basic" => "$20", "Plus" => "$40" }, "$40") # => <option value="$20">Basic</option> # => <option value="$40" selected="selected">Plus</option> options_for_select([ "VISA", "MasterCard", "Discover" ], ["VISA", "Discover"]) # => <option selected="selected" value="VISA">VISA</option> # => <option value="MasterCard">MasterCard</option> # => <option selected="selected" value="Discover">Discover</option>
HTMLの属性を付与する際は要素の最後にハッシュで値を渡す
options_for_select([ "Denmark", ["USA", {class: 'bold'}], "Sweden" ], ["USA", "Sweden"]) # => <option value="Denmark">Denmark</option> # => <option value="USA" class="bold" selected="selected">USA</option> # => <option value="Sweden" selected="selected">Sweden</option> options_for_select([["Dollar", "$", {class: "bold"}], ["Kroner", "DKK", {onclick: "alert('HI');"}]]) # => <option value="$" class="bold">Dollar</option> # => <option value="DKK" onclick="alert('HI');">Kroner</option>
check_box_tag(name, value = "1", checked = false, options = {})
radio_button_tag(name, value, checked = false, options = {})
<%= form_for(@book) do |f| %> ラジオボタン: <label><%= f.radio_button :publish, '技術評論社', class: :rd %> 技術評論社</label> <label><%= f.radio_button :publish, '翔泳社', class: :rd %> 翔泳社</label> <label><%= f.radio_button :publish, 'マイナビ', class: :rd %> マイナビ</label><br /> チェックボックス: <label><%= f.check_box :cd, { class: 'chk'}, 'yes', 'no' %> CD付属?</label><br /> <% end %>
submit_tag(value = "Save changes", options = {})
options
- data:
- disabled
- その他のHTML属性
data attributes
- confirm
- disable_with
submit_tag # => <input name="commit" data-disable-with="Save changes" type="submit" value="Save changes" /> submit_tag "Edit this article" # => <input name="commit" data-disable-with="Edit this article" type="submit" value="Edit this article" /> submit_tag "Save edits", disabled: true # => <input disabled="disabled" name="commit" data-disable-with="Save edits" type="submit" value="Save edits" /> submit_tag "Complete sale", data: { disable_with: "Submitting..." } # => <input name="commit" data-disable-with="Submitting..." type="submit" value="Complete sale" /> submit_tag nil, class: "form_submit" # => <input class="form_submit" name="commit" type="submit" /> submit_tag "Edit", class: "edit_button" # => <input class="edit_button" data-disable-with="Edit" name="commit" type="submit" value="Edit" /> submit_tag "Save", data: { confirm: "Are you sure?" } # => <input name='commit' type='submit' value='Save' data-disable-with="Save" data-confirm="Are you sure?" />
form_for(record, options = {}, &block)
注意点
- 対応したルーティングがないとテンプレート読み込み時にエラーが発生する
- Modelの属性に対応したメソッド名(属性名)を指定しないとテンプレート読み込み時にエラーが発生する
text_field(object_name, method, options = {})
例)
text_field(:post, :title, size: 20) # => <input type="text" id="post_title" name="post[title]" size="20" value="#{@post.title}" /> text_field(:post, :title, class: "create_input") # => <input type="text" id="post_title" name="post[title]" value="#{@post.title}" class="create_input" /> text_field(:session, :user, onchange: "if ($('#session_user').val() === 'admin') { alert('Your login cannot be admin!'); }") # => <input type="text" id="session_user" name="session[user]" value="#{@session.user}" onchange="if ($('#session_user').val() === 'admin') { alert('Your login cannot be admin!'); }"/> text_field(:snippet, :code, size: 20, class: 'code_input') # => <input type="text" id="snippet_code" name="snippet[code]" size="20" value="#{@snippet.code}" class="code_input" />
* ActionView::Helpers::FormBuilder
から呼ばれている場合、第一引数が省略できる
<%= form_for @user do |f| %> <%= f.text_field :name, size: 20, calss: 'name_input' %>
select(object, method, choices = nil, options = {}, html_options = {}, &block)
options
- include_blank
- disabled
- selected
<%= form_for(@book) do |f| %> <%= f.select :publish, ['技術評論社', '翔泳社', 'マイナビ'], { include_blank: '選択してください' }, class: 'pub' %> <br /> <%= f.select :publish, { '技術評論社' => 1, '翔泳社' => 2, 'マイナビ' => 3 } %> <br /> <%= f.select(:publish, [['技術評論社', 1], ['翔泳社', 2], ['マイナビ', 3]]) %> <br /> <%= f.select :publish, ['技術評論社', '翔泳社', 'マイナビ'], { include_blank: '選択してください' }, multiple: true %> <% end %>
check_box(object_name, method, options = {}, checked_value = "1", unchecked_value = "0")
radio_button(object_name, method, tag_value, options = {})
collection_select(method, collection, value_method, text_method, options = {}, html_options = {})
options
- include_blank
- disabled
- selected
<%= form_for(@book) do |f| %> <%= f.collection_select :publish, @books, :id, :publish, { include_blank: '選択してください' }, { class: 'select' } %> <% end %>
collection_check_boxes(object, method, collection, value_method, text_method, options = {}, html_options = {}, &block)
collection_radio_buttons(object, method, collection, value_method, text_method, options = {}, html_options = {}, &block)
<%= form_for(@book) do |f| %> <%= f.collection_check_boxes(:publish, @books, :id, :publish) %><br /> <%= f.collection_radio_buttons(:publish, @books, :id, :publish) %> <% end %>
submit(value=nil, options={})
<%= form_for @post do |f| %> <%= f.submit %> <% end %>
ActionView::Helpers
simple_format(text, html_options = {}, options = {})
article = 'TITLE CONTENT1 CONTENT2 CONTENT3' simple_format(article, class: "article article-primary") # <p class="article article-primary">TITLE</p> # <p class="article article-primary">CONTENT1 # <br>CONTENT2 # <br>CONTENT3</p> simple_format("<font color='red'>sanitize</font> is false.", {}, sanitize: false) # <p><font color="red">sanitize</font> is false.</p> simple_format("<font color='red'>sanitize</font> is true.", {}, sanitize: true) # <p>sanitize is true.</p> simple_format('wrappered by div', {}, wrapper_tag: 'div') # <div>wrappered by div</div>
truncate(text, options = {}, &block)
truncate("Once upon a time in a world far far away") # Once upon a time in a world... truncate("Once upon a time in a world far far away", length: 17) # Once upon a time truncate("Once upon a time in a world far far away", length: 17, separator: ' ') # Once upon a... truncate("And they found that many people were sleeping better.", length: 25, omission: '(continued)') # And they found(continued) truncate("<p>Once upon a time in a world far far away</p>") # <p>Once upon a time in a wo... truncate("<p>Once upon a time in a world far far away</p>", escape: false) # <p>Once upon a time in a wo...
* lengthで指定する文字数がomissionの文字数を含む点に注意
excerpt(text, phrase, options = {})
excerpt('hoge0987654321fuga1234567890piyo', 'fuga', radius: 3) # ...321fuga123...
cycle(first_value, *values)
current_cycle(name = "default")
reset_cycle(name = "default")
highlight(text, phrases, options = {})
concat(string)
raw(stringish)
* <%== %> を利用することで同様の結果が得られる
html_escape(s)
* Rails 3 以降<%= %>内では暗黙的にエスケープ処理されているため、基本的に不要
* hはこのメソッドのエイリアス
sanitize(html, options = {})
options
- tag
- attributes
- scrubber
ActionView::Helpers::NumberHelper
number_to_currency(number, options = {})
options
- locale - Sets the locale to be used for formatting (defaults to current locale).
- precision - Sets the level of precision (defaults to 2).
- unit - Sets the denomination of the currency (defaults to “$”).
- separator - Sets the separator between the units (defaults to “.”).
- delimiter - Sets the thousands delimiter (defaults to “,”).
- format - Sets the format for non-negative numbers (defaults to “%u%n”). Fields are %u for the currency, and %n for the number.
- negative_format - Sets the format for negative numbers (defaults to prepending an hyphen to the formatted number given by :format). Accepts the same fields than :format, except %n is here the absolute value of the number.
- raise - If true, raises InvalidNumberError when the argument is invalid.
number_to_currency(1234567890.50) # => $1,234,567,890.50 number_to_currency(1234567890.506) # => $1,234,567,890.51 number_to_currency(1234567890.506, precision: 3) # => $1,234,567,890.506 number_to_currency(1234567890.506, locale: :fr) # => 1 234 567 890,51 € number_to_currency("123a456") # => $123a456 number_to_currency("123a456", raise: true) # => InvalidNumberError number_to_currency(-1234567890.50, negative_format: "(%u%n)") # => ($1,234,567,890.50) number_to_currency(1234567890.50, unit: "R$", separator: ",", delimiter: "") # => R$1234567890,50 number_to_currency(1234567890.50, unit: "R$", separator: ",", delimiter: "", format: "%n %u") # => 1234567890,50 R$
number_to_human(number, options = {})
options
- locale - Sets the locale to be used for formatting (defaults to current locale).
- precision - Sets the precision of the number (defaults to 3).
- significant - If true, precision will be the # of significant_digits. If false, the # of fractional digits (defaults to true)
- separator - Sets the separator between the fractional and integer digits (defaults to “.”).
- delimiter - Sets the thousands delimiter (defaults to “”).
- strip_insignificant_zeros - If true removes insignificant zeros after the decimal separator (defaults to true)
- units - A Hash of unit quantifier names. Or a string containing an i18n scope where to find this hash. It might have the following keys:
- integers: :unit, :ten, :hundred, :thousand, :million, :billion, :trillion, :quadrillion
- fractionals: :deci, :centi, :mili, :micro, :nano, :pico, :femto
- format - Sets the format of the output string (defaults to “%n %u”). The field types are:
- %u - The quantifier (ex.: 'thousand')
- %n - The number
- raise - If true, raises InvalidNumberError when the argument is invalid.
number_to_human(123) # => "123" number_to_human(1234) # => "1.23 Thousand" number_to_human(12345) # => "12.3 Thousand" number_to_human(1234567) # => "1.23 Million" number_to_human(1234567890) # => "1.23 Billion" number_to_human(1234567890123) # => "1.23 Trillion" number_to_human(1234567890123456) # => "1.23 Quadrillion" number_to_human(1234567890123456789) # => "1230 Quadrillion" number_to_human(489939, precision: 2) # => "490 Thousand" number_to_human(489939, precision: 4) # => "489.9 Thousand" number_to_human(1234567, precision: 4, significant: false) # => "1.2346 Million" number_to_human(1234567, precision: 1, separator: ',', significant: false) # => "1,2 Million" number_to_human(500000000, precision: 5) # => "500 Million" number_to_human(12345012345, significant: false) # => "12.345 Billion"
number_to_human_size(number, options = {})
options
- locale - Sets the locale to be used for formatting (defaults to current locale).
- precision - Sets the precision of the number (defaults to 3).
- significant - If true, precision will be the # of significant_digits. If false, the # of fractional digits (defaults to true)
- separator - Sets the separator between the fractional and integer digits (defaults to “.”).
- delimiter - Sets the thousands delimiter (defaults to “”).
- strip_insignificant_zeros - If true removes insignificant zeros after the decimal separator (defaults to true)
- prefix - If :si formats the number using the SI prefix (defaults to :binary)
- raise - If true, raises InvalidNumberError when the argument is invalid.
number_to_human_size(123) # => 123 Bytes number_to_human_size(1234) # => 1.21 KB number_to_human_size(12345) # => 12.1 KB number_to_human_size(1234567) # => 1.18 MB number_to_human_size(1234567890) # => 1.15 GB number_to_human_size(1234567890123) # => 1.12 TB number_to_human_size(1234567890123456) # => 1.1 PB number_to_human_size(1234567890123456789) # => 1.07 EB number_to_human_size(1234567, precision: 2) # => 1.2 MB number_to_human_size(483989, precision: 2) # => 470 KB number_to_human_size(1234567, precision: 2, separator: ',') # => 1,2 MB number_to_human_size(1234567890123, precision: 5) # => "1.1228 TB" number_to_human_size(524288000, precision: 5) # => "500 MB"
number_to_percentage(number, options = {})
options
- locale - Sets the locale to be used for formatting (defaults to current locale).
- precision - Sets the precision of the number (defaults to 3).
- significant - If true, precision will be the # of significant_digits. If false, the # of fractional digits (defaults to false).
- separator - Sets the separator between the fractional and integer digits (defaults to “.”).
- delimiter - Sets the thousands delimiter (defaults to “”).
- strip_insignificant_zeros - If true removes insignificant zeros after the decimal separator (defaults to false).
- format - Specifies the format of the percentage string The number field is %n (defaults to “%n%”).
- raise - If true, raises InvalidNumberError when the argument is invalid.
number_to_percentage(100) # => 100.000% number_to_percentage("98") # => 98.000% number_to_percentage(100, precision: 0) # => 100% number_to_percentage(1000, delimiter: '.', separator: ',') # => 1.000,000% number_to_percentage(302.24398923423, precision: 5) # => 302.24399% number_to_percentage(1000, locale: :fr) # => 1 000,000% number_to_percentage("98a") # => 98a% number_to_percentage(100, format: "%n %") # => 100.000 % number_to_percentage("98a", raise: true) # => InvalidNumberError
number_to_phone(number, options = {})
options
- area_code - Adds parentheses around the area code.
- delimiter - Specifies the delimiter to use (defaults to “-”).
- extension - Specifies an extension to add to the end of the generated number.
- country_code - Sets the country code for the phone number.
- raise - If true, raises InvalidNumberError when the argument is invalid.
number_to_phone(5551234) # => 555-1234 number_to_phone("5551234") # => 555-1234 number_to_phone(1235551234) # => 123-555-1234 number_to_phone(1235551234, area_code: true) # => (123) 555-1234 number_to_phone(1235551234, delimiter: " ") # => 123 555 1234 number_to_phone(1235551234, area_code: true, extension: 555) # => (123) 555-1234 x 555 number_to_phone(1235551234, country_code: 1) # => +1-123-555-1234 number_to_phone("123a456") # => 123a456 number_to_phone("1234a567", raise: true) # => InvalidNumberError number_to_phone(1235551234, country_code: 1, extension: 1343, delimiter: ".") # => +1.123.555.1234 x 1343 number_to_phone(75561234567, pattern: /(\d{1,4})(\d{4})(\d{4})$/, area_code: true) # => "(755) 6123-4567" number_to_phone(13312345678, pattern: /(\d{3})(\d{4})(\d{4})$/)) # => "133-1234-5678"
number_with_delimiter(number, options = {})
options
- locale - Sets the locale to be used for formatting (defaults to current locale).
- delimiter - Sets the thousands delimiter (defaults to “,”).
- separator - Sets the separator between the fractional and integer digits (defaults to “.”).
- raise - If true, raises InvalidNumberError when the argument is invalid.
number_with_delimiter(12345678) # => 12,345,678 number_with_delimiter("123456") # => 123,456 number_with_delimiter(12345678.05) # => 12,345,678.05 number_with_delimiter(12345678, delimiter: ".") # => 12.345.678 number_with_delimiter(12345678, delimiter: ",") # => 12,345,678 number_with_delimiter(12345678.05, separator: " ") # => 12,345,678 05 number_with_delimiter(12345678.05, locale: :fr) # => 12 345 678,05 number_with_delimiter("112a") # => 112a number_with_delimiter(98765432.98, delimiter: " ", separator: ",") # => 98 765 432,98 number_with_delimiter("112a", raise: true) # => raise InvalidNumberError
number_with_precision(number, options = {})
options
- locale - Sets the locale to be used for formatting (defaults to current locale).
- precision - Sets the precision of the number (defaults to 3).
- significant - If true, precision will be the # of significant_digits. If false, the # of fractional digits (defaults to false).
- separator - Sets the separator between the fractional and integer digits (defaults to “.”).
- delimiter - Sets the thousands delimiter (defaults to “”).
- strip_insignificant_zeros - If true removes insignificant zeros after the decimal separator (defaults to false).
- raise - If true, raises InvalidNumberError when the argument is invalid.
number_with_precision(111.2345) # => 111.235 number_with_precision(111.2345, precision: 2) # => 111.23 number_with_precision(13, precision: 5) # => 13.00000 number_with_precision(389.32314, precision: 0) # => 389 number_with_precision(111.2345, significant: true) # => 111 number_with_precision(111.2345, precision: 1, significant: true) # => 100 number_with_precision(13, precision: 5, significant: true) # => 13.000 number_with_precision(111.234, locale: :fr) # => 111,234 number_with_precision(13, precision: 5, significant: true, strip_insignificant_zeros: true) # => 13 number_with_precision(389.32314, precision: 4, significant: true) # => 389.3 number_with_precision(1111.2345, precision: 2, separator: ',', delimiter: '.') # => 1.111,23
strftime(format)
ActionView::Helpers::UrlHelper
link_to(name = nil, options = nil, html_options = nil, &block)
options
data - This option can be used to add custom data attributes.
confirm: 'question?' - This will allow the unobtrusive JavaScript driver to prompt with the question specified (in this case, the resulting text would be question?. If the user accepts, the link is processed normally, otherwise no action is taken.
disable_with - Value of this parameter will be used as the value for a disabled version of the submit button when the form is submitted. This feature is provided by the unobtrusive JavaScript driver.
method: symbol of HTTP verb - This modifier will dynamically create an HTML form and immediately submit the form for processing using the HTTP verb specified. Useful for having links perform a POST operation in dangerous actions like deleting a record (which search bots can follow while spidering your site). Supported verbs are :post, :delete, :patch, and :put. Note that if the user has JavaScript disabled, the request will fall back to using GET. If href: '#' is used and the user has JavaScript disabled clicking the link will have no effect. If you are relying on the POST behavior, you should check for it in your controller's action by using the request object's methods for post?, delete?, patch?, or put?.
remote: true - This will allow the unobtrusive JavaScript driver to make an Ajax request to the URL in question instead of following the link. The drivers each provide mechanisms for listening for the completion of the Ajax request and performing JavaScript operations once they're complete
link_to_if(condition, name, options = {}, html_options = {}, &block)
link_to_unless(condition, name, options = {}, html_options = {}, &block)
link_to_unless_current(name, options = {}, html_options = {}, &block)
mail_to(email_address, name = nil, html_options = {}, &block)
options
- subject - Preset the subject line of the email.
- body - Preset the body of the email.
- cc - Carbon Copy additional recipients on the email.
- bcc - Blind Carbon Copy additional recipients on the email.
ActionView::Helpers::AssetTagHelper
audio_tag(*sources)
options
video_tag(*sources)
options
- poster - Set an image (like a screenshot) to be shown before the video loads. The path is calculated like the src of image_tag.
- size - Supplied as “{Width}x{Height}” or “{Number}”, so “30x45” becomes width=“30” and height=“45”, and “50” becomes width=“50” and height=“50”. :size will be ignored if the value is not in the correct format.
ActionView::Helpers::AssetUrlHelper
auto_discovery_link_tag(type = :rss, url_options = {}, tag_options = {})
options
- rel - Specify the relation of this link, defaults to “alternate”
- type - Override the auto-generated mime type
- title - Specify the title of the link, defaults to the type
favicon_link_tag(source='favicon.ico', options={})
options
path_to_asset(source, options = {})
asset_path
メソッドのエイリアス
options
- type
- host
asset_url "application.js" # => http://example.com/assets/application.js asset_url "application.js", host: "http://cdn.example.com" # => http://cdn.example.com/assets/application.js
※ 他のpath_to〜メソッドは、このメソッドを呼び出している
例)path_to_audio
# path_to_audioはaudio_pathのエイリアス def audio_path(source, options = {}) path_to_asset(source, {type: :audio}.merge!(options)) end
path_to_audio(source, options = {})
path_to_font(source, options = {})
path_to_image(source, options = {})
path_to_javascript(source, options = {})
path_to_stylesheet(source, options = {})
path_to_video(source, options = {})
その他のActionView::Helpers
debug(object)
options
capture(*args)
options
tag(name, options = nil, open = false, escape = true)
options
content_tag(name, content_or_options_with_block = nil, options = nil, escape = true, &block)
options
ViewHelperの実装
- app/helpersディレクトリ配下に「xxxxx_helper.rb」というファイル名で作成する
- 設定ファイル(application.rb)のconfig.action_controller.include_all_helpers = false
module ViewHelper def format_datetime(datetime, type = :datetime) return '' unless datetime case type when :datetime format = '%Y年%m月%d日 %H:%M:%S' when :date format = '%Y年%m月%d日' when :time format = '%H:%M:%S' end datetime.strftime(format) end def list_tag(collection, prop) content_tag(:ul) do collection.each do |element| concat content_tag(:li, element.attributes[prop]) end end end def list_tag2(collection, prop) list = '<ul>' collection.each do |element| list.concat('<li>') list.concat(h element.attributes[prop]) list.concat('</li>') end raw list.concat('</ul>') end def blockquote_tag(cite, citetext, options = {}, &block) options.merge! cite: cite quote_tag = content_tag(:blockquote, capture(&block), options) p_tag = content_tag(:p) do concat '出典:' concat content_tag(:cite, citetext) end quote_tag.concat(p_tag) end def blockquote_tag2(cite, citetext, body = '', options = {}, &block) options.merge! cite: cite quote_tag = content_tag(:blockquote, block_given? ? capture(&block) : body, options) end end
JBuiler
JSONの生成
json.key(value)
json.extract!(obj, prop[, ...])
index.json.jbuilder
json.array!(@books) do |book| json.extract! book, :isbn, :title, :price, :publish, :published, :cd json.url book_url(book, format: :json) end
[ { "isbn":"978-4-7741-5878-5", "title":"AndroidエンジニアのためのモダンJava", "price":3360,"publish":"技術評社", "published":"2013-08-20", "cd":false, "url":"http://localhost:3000/books/1.json" }, . . .
Builder
XMLの生成
xml.element([content] [, attr: value, ...]) do &block
index.xml.builder
xml.books do @books.each do |book| xml.book(isbn: book.isbn) do xml.title(book.title) xml.price(book.price) xml.publish(book.publish) xml.published(book.published) xml.cd(book.cd) end end end
<?xml version="1.0" ?> <books> <book isbn="978-4-7741-5878-5"> <title>AndroidエンジニアのためのモダンJava</title> <price>3360</price> <publish>技術評論社</publish> <published>2013-08-20</published> <cd>false</cd> </book> . . .
Sprockets
マニフェスト
app/assets/javascripts/application.js
//= require jquery //= require jquery_ujs //= require turbolinks //= require_tree .
app/assets/stylesheets/application.css
/* *= require_self *= require_tree . */
ディレクティブ
ディレクティブ | 概要 |
---|---|
require path | 指定したファイルを一度だけ読み込み |
include path | 指定したファイルを読み込み |
require_directory path | 指定したフォルダ内のファイルをアルファベット順に読み込み |
require_tree path | 指定されたフォルダ配下を再帰的に読み込み |
require_self | 現在のファイルの内容をrequire /include の前に挿入 |
マニフェスト経由でアセットを読み込む
javascript_include_tag
stylesheet_link_tag
layouts/application.html.erb
<%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => true %> <%= javascript_include_tag "application", "data-turbolinks-track" => true %>
data-turbolinks-track
はturbolinks
を有効にするか。
media
はスタイルシートを出力する対象を指定。
キャッシュ
設定
# キャッシュの有効化 config.action_controller.perform_caching = true # キャッシュの格納先 config.cash_store = :memory_store
cache(name = {}, options = {}, &block)
ページ内で複数キャッシュがある場合、suffix
を設定し、キャッシュキーの重複を避ける
現在時刻(キャッシュなし):<%= Time.now %><br /> <% cache do %> <%# cache(suffix: 'footer') do %> 現在時刻(キャッシュあり):<%= Time.now %><br /> <% end %>
複数ページでの共有
キャッシュする内容をパーシャルにし、それぞれのページで読み込む
_share.html.erb
<% cache('GlobalTime') do %> 現在時刻(キャッシュあり):<%= Time.now %><br /> <% end %>
share1.html.erb
現在時刻(キャッシュなし):<%= Time.now %><br /> <%= render 'share' %>
share2.html.erb
現在時刻(キャッシュなし):<%= Time.now %><br /> <%= render 'share' %>
モデルによるキャッシュキーの生成
cache
メソッドの引数にモデルのインスタンスを渡す。
キャッシュキーが「モデル/id-update_at/ハッシュ値」のようになる
<% cache(book) do %> <img src="http://www.wings.msn.to/books/<%= book.isbn%>/<%= book.isbn%>_logo.jpg" width="80" height="30" /><br /> <%= book.title %><br /> <%= book.publish %>/発行<br /> 定価 <%= book.price %>円(税込)<br /> ISBN <%= book.isbn %><br /> 発刊日: <%= book.published %> レビュー:<ul><%= render book.reviews %></ul> <% end %>
cache_if(condition, name = {}, options = {}, &block)
条件に応じてキャッシュする。
<% cache_if(book.published <= Date.today ,book) do %> <img src="http://www.wings.msn.to/books/<%= book.isbn%>/<%= book.isbn%>_logo.jpg" width="80" height="30" /> <br /> <%= book.title %> <br /> <%= book.publish %>/発行 <br /> 定価 <%= book.price %>円(税込) <br /> ISBN <%= book.isbn %> <br /> 発刊日: <%= book.published %> レビュー:<ul><%= render book.reviews %></ul> <% end %>
fields_for(record_name, record_object = nil, options = {}, &block)
<%= form_for(@user, url: { action: :create }) do |f| %> <div class="field"> <%= f.label :username, 'ユーザ名' %><br /> <%= f.text_field :username %> </div> <div class="field"> <%= f.label :email, 'メールアドレス:' %><br /> <%= f.text_field :email %> </div> <%= field_set_tag '著者情報' do %> <%= fields_for @user.author do |af| %> <div class="field"> <%= af.label :name, '著者名:' %><br /> <%= af.text_field :name %> </div> <div class="field"> <%= af.label :birth, '誕生日:' %><br /> <%= af.text_field :birth %> </div> <% end %> <% end %> <%= f.submit '登録' %> <% end %>
5.1. テスト
# 各テストの実行前に呼び出される def setup end # 各テストの実行後に呼び出される def taardown end # テスト test 'test_name' do # テストコード end
model
メソッド
assert
controller
メソッド
assert_difference(expression, difference = 1, message = nil, &block)
assert_no_difference(expression, message = nil, &block)
integration
rails g integration_test [name]
メソッド
follow_redirect!
5.2. メーラー
ActionMailerの作成
rails g mailer [name] [method] [options]
設定
Rails.application.configure do # デフォルトのメールヘッダ config.action_mailer.default_options = {} # メールを実際に送信するか (デフォルト: true) config.action_mailer.perform_deliveries = true # メール配信失敗時にエラーを発生させるか (デフォルト: false) config.action_mailer.raise_delivery_errors = true # メールテンプレート(url_for)に利用されるホスト名 config.action_mailer.default_url_options = { host: 'sample.com' } # メールの送信情報 (デフォルト: smtp) #ActionMailer::Base.delivery_method = :smtp config.action_mailer.delivery_method = :smtp # smtpの設定 #ActionMailer::Base.smtp_settings = config.action_mailer.smtp_settings = { user_name: ENV['SENDGRID_USERNAME'], password: ENV['SENDGRID_PASSWORD'], domain: "heroku.com", address: "smtp.sendgrid.net", port: 587, authentication: :plain, enable_starttls_auto: true } end
メソッド
default(value = nil)
mail(headers = {}, &block)
attachments()
deliver()
mailers/hoge_mailer.rb
class HogeMailer < ActionMialer::Base # デフォルトのメールヘッダ指定 default from: 'hoge@example.com', cc: 'fuga@example.com' def sendmail_confirm # ファイルの添付 attachments['hoge.png'] = File.read Rails.root.join('/hoge.png') # ファイルのインライン添付 attachments.inline['fuga.png'] = File.read Rails.root.join('/fuga.png') # Mail::Message オブジェクトの作成 mail from: 'from@example.com', to: 'to@example.com' end
controllers/hoge_controller.rb
class HogeController < ApplicationController def create user = User.find 1 # メールの送信実行 HogeMailer.sendmail_confirm(user).deliver
views/hoge_mailer/sendmail_confirm.html.erb
<h1>title</h1> <%# インライン添付 %> <%= image_tag attachments['fuga.png'].url %>
インターセプタ
config/initializers/test_mail_config.rb
mailers/hoge_interceptor