- Railsの各コンポーネント(ActiveRecordやActionPack)の説明や、MVCにおける基礎的な知識
- ActiveRecord
- ActionPack
- Action Dispatch
- Action Controller
- Active Support Core Extensions
- blank? false, nil, 空白, 空の配列, 空のハッシュ, empty?
- present?
- presence nil or 実体
- h html_escapeのalias
- html_safe 「安全」印を付ける.ビューにそのまま表示する.
- html_safe?
- try nvlみたいな感じ(nはnil) Ruby2.3では&.が使える?
- try! 存在しないメソッドの場合は例外
- in?
- delegate :method1, :medhod2 to: :target (target.methodが呼ばれるようになる)
- cattr_accessor :name クラスプロパティ # 値の設定は一度だけ実行される
- cattr_accessor :name do ... end
- Railities
- Railsの起動プロセス、CLI、ジェネレータなど
- ディレクトリ構造の説明
- app/
- controllers/
- assets, mailers
- controllers/
- bin/
- config/
- routes.rb, database.yml, environments, ...
- config.ru
- db/
- schema.rb, ~.sqlite3
- migrate/
- seeds.rb
- Gemfile
- Gemfile.lock
- lib/
- log/
- public/
- Rakefile
- README.rdoc
- test/
- fixtures/ (*.yaml)
- tmp/
- cache/, pid/, sessions/
- vendor/
- app/
- rake、railsコマンド
- rake
- T --tasks
- D --describe
- stats
- notes
- db
- :seed
- :setup
- rails
- c console
- d destroy
- g generate
- controller
- model Item name:string{10}:uniq price:decimal{5,2} vendor:references:index
- view
- scaffold
- new
- r --ruby
- m --template
- B --skip-bundle
- G --skip-git
- O --skip-active-record
- S --skip-sprockets
- d --database
- s --skip
- h --help
- v --version
- r runner
- s server
- rake
- ActiveSupport
- ActiveRecordの構造
- CUコールバック
- before_validation
- after_validation
- before_save
- around_save
- before_create / before_update
- around_create /
- after_create /
- after_save
- Dコールバック
- before_destroy
- around_destroy
- after_destroy
- CUコールバック
- モデルの定義
- inet, cidr, macaddr
- composed_of :user, class_name: 'User', mapping: ['username', 'name'] # class_nameは省略可
- リレーション
- belongs_to, has_one
- hmt(has_many, through)
- habtm(has_and_belongs_to_many)
- ポリモーフィック関連
- rails g model Picture img:references{polymorphic}
- ↑ create_table :pictures do |t| t.references :img, polymorphic: true, index: true
- ↑ 同義 t.integer :img_id \n t.string :img_type
- class Employee has_many :pictures, as: img
- class Product has_many :pictures, as: img
- バリデーション
- validates :hoge, :presence true, if: -> {@foo.blank?}
- バリデーションヘルパー
- presence
- absense
- length { minimum:0, maximum: 10}
- numericality { greater_than_or_equal_to: 0 }
- format {with: /\A hoge \z/}
- confirmation
- hoge_confirmation
- inclusion {in: []} / inclusion []
- exclusion
- acceptance
- uniqueness
- create(戻り値false), create!(例外)
- valid?
- カスタムバリデーション
- ActiveModel::Validator モデル単位
- validates_with HogeValidator
- class HogeValidator < ActiveModel::Validator
- def validate(record) record.errors[:fieldname] = 'error msg'
- ActiveModel::EachValidator フィールド単位
- validates: hoge, foo_bar: true
- class FooBarValidator < ActiveModel::EachValidator
- def validate_each(record, attribute, value) record.errors[attribute] = 'error msg'
- ActiveModel::Validator モデル単位
- model.errors.full_messages # ['aaa', 'bbb', 'Field ccc']
- モジュール
- ActiveModel::Model, ActiveModel::Validation
- CRUD操作
- find # id配列を渡すと、全て存在するなら配列が返ってくる
- find_by # 常に一つ
- find_by_sql(sql), find_by_sql([sql, param]) # 常に複数
- find_each # 常にidで昇順
- pluck
- select # モデルのインスタンスが返る
- ids
- includes(:hoges)
- joins(:hoges)
- t = Item.arel_table \ Item.where(t[:id].eq(8).or t[:id].eq(9))
- where.not
- ActiveRecord::Base.connection.select_rows("select * from hoges") #
- ActiveRecord::Base.connection.select_values # rowsとは違い、最初の列の値のみ取得
- スコープ
- scope :s1, ->(val){ where("hoge") }
- default_scope {}
- Item.unscope
- マイグレーション
- yyyyMMddHHmmss_add_hoge_to_items.rb
- schema_migrations
- rake:db version
- CreateHoge, AddHogeToItems, RemoveHogeFromItems, CreateJoinTableHogeFoo
- rails destroy migration CreateHoge
- def change
- create_table :items do |t|
- t.string :hoge, limit: 20
- t.decimal :val, precision:5, scale: 1
- rename_column :items, :price, :value
- add_column, add_index, add_reference, add_timestamps
- create_table, create_join_table
- drop_table, drop_join_table
- remove_reference, remove_timestamps
- rename_column, index, table
- create_table :items do |t|
- トランザクション
- optimistic locking
- lock_version # デフォルト値0を入れる, 名前変更可能
- optimistic locking
- config/routes.rb
- resources :items # index, show, new, create, edit, update, destroy
- only: [:index, :show]
- except: [:create, :edit, :destroy]
- constraints: {id: /[1-9]/}
- format: false # /items/1.mp3 <- 不可
- format: true # /items/1.mp3 <- 必須
- controller: :i # i#index
- as: :i # i_index
- resources :hoge do
- collection do get 'foo' end
- member do get 'bar' end
- get :foobar, on: :new # /hoge/new/foobar
- get :foobar, on: :callection # /hoge/foobar
- get :foobar, on: :member # /hoge/1/foobar
- end
- resurces :items do
- resources hoges # /items/1/hoges/1
- shallow do
- resources :items do
-
resources :hoges - namespace :foo do
- resources :items # foo_items_index /foo/items foo/items#index
- scope :foo do
- resources :items # items_index /foo/items items#index
- scope module: :foo do
- resources :items # items_index /items foo/items#index
- concern :hogeable do # 名前付け
- collection do
-
get 'hoge' # resources :items, concerns: :hogeable
- resource :item # show, create, edit, update, destroy # show(:id)は無い
- root to: redirect('foo/bar')
- root to: 'items#index'
- get '/:action(.:format)', controller: :items
- get '/にほんご', to: 'foo/bar#index'
- match '/u', to: 'items#index', via: :get # matchはvia必須
- root_path # /
- item_path # /item
- item_url(1) # http://example.com/items/1
- new_item_url # http://example.com/items/new
- resources :items # index, show, new, create, edit, update, destroy
- RESTとコントローラ
- request.headers['User-Agent']
- request.headers['HTTP_USER_AGENT']
- response.headers['Content-Type'] = 'application/pdf'
- パラメータ
- クエリパラメータ(url?keyword=ruby&hoge[]=1&hoge[]=2&foo[bar]=3)
- request.query_parameters
- パスパラメータ(/:action/.format)
- request.path_parameters
- リクエストパラメータ(Postのbody)
- request.request_parameters
- 全部
- params
- params.fetch(:sonzaisinai) # ParameterMissing例外
- params.fetch(:hoge, "default value") # デフォルト値設定
- Mass Assignment
- require(:hoge) # :hogeがない場合はParameterMissing例外
- permit(:foo, :bar) # :foo, :barだけに絞る
- params.require(:user).permit(:name, :age) # みたいに使う
- クエリパラメータ(url?keyword=ruby&hoge[]=1&hoge[]=2&foo[bar]=3)
- コントローラとデータの入出力
- render 'index' # 'index'は省略可 # この行自体省略可
- @x = 10 # Viewで使用可能
- render(locals: {x: 10} ) # Viewで使用可能
- render(partial: 'layout', locals: {x:10}) # Partialで使用可能
- render html: '<%= "OK" %>' # htmlエスケープされる
- render plain: # そのまま
- render inline: # OKだけ
- render content_type: 'text/plain' # とかできる
- render action: :index # index.html.erbをレンダリング
- render :index # action:は省略可能
- render template 'hoge/foo'
- render file '/var/hoge/foo.html.erb'
- url_for # コントローラとビューで使える
- controller: :hoge
- action: :foo
- only_path # trueなら/コントローラ以降のみ
- 'items#index' # これはできない!!
- url_for(:back) # javascript:history.back()
- url_for hoge_path(114514) # ヘルパー使うことが多い
- redirect_to # url_forと同じオプションを使用できる
- メディアタイプに合わせた出力フォーマット
- respond_to do |format|
- format.xml { render xml: hoge }
- format.json { render xml: hoge }
- フィルタ
- before_action :hoge_check, except: [:foo]
- skip_before_action :hoge_check, only: [:bar]
- before_action内でrenderを呼ぶとactionが呼ばれない
- around_action
- yield # このタイミングでactionが呼ばれる
- http_basic_authenticate_with name: "user", password: "pass"
- before_action :auth
- def auth
- authenticate_or_request_with_http_basic("hoge") do |user, pass|
-
user == "user" && pass == "pass"
セッション- sessions[:count] = 1
- sessions[:count] = nil # del
- reset_session # delete all session
- Rails.application.config.session_store : cookie_store, key: 'hoge', expire_after: 2.hours
- cookies[:count] = "1"
- cookies[:count] = { value: "1", expire: 1.hour.from_now, secure: true, httponly: true } # https only, can't access from js
- cookies.delete(:count)
- cookies.signed[:count] = 1
- ERBによるHTMLの出力
- <%#= hoge %>
- <% if false %> <%= foo %> <% end %>
- <% =begin %> <%= foo %> <% =end %>
- <%== hoge %> # escapeされない
- <%= raw(hoge) %> # escapeされない
- <%= hoge.html_safe %> # escapeされない
- レイアウト
- app/view/layout/application.html.erb # デフォルト
- app/view/layout/{{controller}}.html.erb # 優先
- render layout: hoge # 最優先
- コントローラの layout オーバーロード(layout 'hoge', except: :edit) # 優先
- <%= yield :hoge %> # ↓を読み込む (レイアウト)
- <%= content_for :hoge do %> # ↑に読み込まれる (ビューテンプレート)
- <%= if content_for? hoge %> # 分岐もできる
- JSONの出力
- jbuilderはRails4デフォルト
- json.name @user[:name] # hoge.json.jbuilder
- ヘルパー
- <%= form_for :form do |f| %> # authenticity_tokenが隠しフィールドとして作られる
- # 手動で作る
- f.text_field :name, size: 40 # id="form_name" name="form[name]" size=40
- f.text_area :message, size: "40x3" # cols="40" rows="3"
- f.hidden_field :secret
- f.password_field :password
- f.check_box :hoge
- f.radio_button :foo
- f.label :hoge, "ほげ"
- f.collection_radio_buttons(:item, item.all, :name, :price)
- f.button "fooooo", type: :reset # default submit
- f.button(type: 'button') do
- content_tag(:strong, 'ほげ') # ほげ
- f.submit # button, submitは Create User, Update Userとか表示される
- f.range_field :range, min: 0, max: 100, step: 20
- f.search_field :keyword
- f.date_field :date
- f.telephone_field :tel # input type="tel"
- f.select :rank, ["a", "b"] # a</>b</> f.select :color, {"a" => "red", }, {include_blank: "foo"} # foo</>a</>
- f.collection_select(:area, Area.all, :id, :name)
- image_tag 'logo.png', alt: "logo", width: 320, height: 240 # /app/assets/images/logo.png
- image_tag 'logo.png', alt: "logo", size: "320x240" # ↑と同じ
- image_tag 'logo.png' # alt="logo.png"
- form_for @order do |f| # accepts_nested_attributes_for :order_details
- f.fields_for :order_details do |builder| # @order.order_details
-
builder.text_field :item # @order.order_details[i].item -
builder.number_field :count # @order.order_details[i].count - ↑のコントローラ params.require(:order).permit({order_details_attributes: [:id, :item, :count]})
- app/helpers
- helper_method :hoge # viewで使用できるようにする
- app/controllers/concerns
- module Hello # コントローラ側でinclude Helloするとhelloが使える
- extend ActiveSupport::Concern
- included do
-
helper_method :hello - end
- private def hello
- end
その他- フラグメントキャッシング
- ビュー内のブロック単位のキャッシング、デフォルトではproductionのみ
- config/environments/development.rb config.action_controller.perform_caching = true
- <% cache do %> # <% cache('key') do %> とすると、キャッシュブロックを分けられる
- キャッシュされる
- <% end %>
- config.cache_store = :file_store # default時(tmp/cache) :memory_storeに変更できる
- expire_fragment(controller: 'hoge', action: 'index', action_suffix: 'key') # キャッシュを期限切れにする
- ディレクティブ
- *= require_tree . # カレントディレクトリ以下を再帰的に読み込む
- *= require_self # このファイルを読み込む
- *= require jquery # gem jquery を読み込む
- *= require_directory # 指定したディレクトリ
- *= include # 指定したファイル
- *= でも //= でも #= でもいい
- <%= style_sheet_link_tag 'application' %> # 読み込む
- <%= javascript_include_tag 'application' %>
- ajax
- gem 'jquery-rails'
- *= require jquery_ujs
- <%= link_to '削除', user, method: :delete, remote: true %> # data-remote: はAjaxで実行される
- コントローラ側で respond_to do |format| format.js {render text: ''} # Ajaxリクエストに応答
- Ajaxの結果はajax:success, ajax:errorイベントとかをjs側で使う
- フラグメントキャッシング
- (メール)
- rails g mailer UserMailer welcome
- config/environments/development.rb
- config.action_mailer.smtp_settings = { address: '', port: , user_name: '', password: '''}
- config.action_mailer.delivery_method = :smtp # :sendmail, :file, :test
- attatchments['hoge.png'] = File.read("/Users/hoge.png") # ビューでは
- attatchments.inline['foo.png'] = File.read("/Users/foo.png") # <%= image_tag attachments['foo.png'].url %>
- def receive(email)
- p email.subject, email.body
- if email.has_attachments?
- メールの送信
- welcome.deliver
- ユニットテストにおけるテスト手法
- class HogeTest < ActiveSupport::TestCase
- test "fooo bar test" do
-
assert_equal "lllllllll" - rake test # testは省略可
- BACKTRACE=1 rake test # 完全なバックトレースを表示する
- モデルのテストとコントローラのテスト
- test/models
- test "hoge foo bar" do
- user = User.create(name: '')
- assert_equal('', user.name)
- assert user.errors.any?
- assert user.errors[:nae].include? "can't be blank"
- test "hoge" do
- assert_difference('User.count', 1) do # 1増えるのを確認
-
user = User.create(name: 'taro')
- test/controllers
- class HogeControllerTest < ActionController::TestCase
- test "foooo" do
-
get :new # get :post, get :patch, get :delete, ... -
assert_response :success # :redirect, :missing, :error -
assert_select('form') -
assert_select("form input[name='user[name]']")
- test/models
ヘルパー- ActiveSupport::Testing::Assertions
- assert_difference, assert_no_difference, assert_not
- Rails::Generators::Testing::Assertions
- asser_class_method, assert_directory, ...
- minitest/unitのリファレンスを読むこと
- ActiveSupport::Testing::Assertions
- composed_of