Ruby on Rails
ActionController
サーチ…
前書き
Action ControllerはMVCのCです。ルータが要求に使用するコントローラを決定した後、コントローラは要求を理解して出力を生成します。
コントローラは要求を受け取り、モデルからデータをフェッチまたは保存し、ビューを使用して出力を作成します。コントローラは、モデルとビューの間の仲介者と考えることができます。モデルデータをビューで使用できるようにしてユーザーに表示し、ユーザーデータをモデルに保存または更新します。
HTMLの代わりにJSONを出力する
class UsersController < ApplicationController def index hashmap_or_array = [{ name: "foo", email: "[email protected]" }] respond_to do |format| format.html { render html: "Hello World" } format.json { render json: hashmap_or_array } end end end
さらに、ルートが必要になります:
resources :users, only: [:index]
これは/users
上のリクエストに対して2つの異なる方法で応答し/users
:
-
/users
または/users.html
アクセスすると、Hello World
のコンテンツを含むhtmlページが表示されます -
/users.json
にアクセスすると、以下を含むJSONオブジェクトが表示されます。
[ { "name": "foo", "email": "[email protected]" } ]
あなたのルートがJSONリクエストだけに答えるformat.html { render inline: "Hello World" }
は、 format.html { render inline: "Hello World" }
を省略することができます。
コントローラ(基本)
class UsersController < ApplicationController def index respond_to do |format| format.html { render html: "Hello World" } end end end
これは基本的なコントローラであり、以下のルートが追加されています(routes.rb内)。
resources :users, only: [:index]
URL /users
アクセスすると、 Hello World
メッセージがWebページに表示され/users
パラメーター
コントローラはHTTPパラメータにアクセスできます(URLで?name=foo
として認識されるかもしれませんが、Ruby on Railsもさまざまなフォーマットを処理します)。 GETパラメータとPOSTパラメータを区別する方法はありませんが、どのような場合でもそれを行うべきではありません。
class UsersController < ApplicationController
def index
respond_to do |format|
format.html do
if params[:name] == "john"
render html: "Hello John"
else
render html: "Hello someone"
end
end
end
end
end
いつものように私たちのルート:
resources :users, only: [:index]
URL /users?name=john
アクセスします/users?name=john
と出力はHello John
、access /users?name=whatever
と出力はHello someone
なります
フィルタリングパラメータ(基本)
class UsersController < ApplicationController def index respond_to do |format| format.html do render html: "Hello #{ user_params[:name] } user_params[:sentence]" end end end private def user_params if params[:name] == "john" params.permit(:name, :sentence) else params.permit(:name) end end end
いくつかのパラメータを許可(または拒否)することで、必要なものだけを通過させることができ、変更するつもりはないユーザー設定オプションのような驚きはありません。
訪問/users?name=john&sentence=developer
表示されますHello john developer
しかし訪れ、 /users?name=smith&sentence=spy
表示するHello smith
ので、唯一の:sentence
あなたのようにアクセスするときにのみ許可されているjohn
リダイレクト
ルートを想定します。
resources :users, only: [:index]
以下を使用して別のURLにリダイレクトすることができます。
class UsersController def index redirect_to "http://stackoverflow.com/" end end
ユーザーが訪問した前のページに戻ることができます:
redirect_to :back
Rails 5では、リダイレクトするための構文が異なることに注意してください。
redirect_back fallback_location: "http://stackoverflow.com/"
前のページにリダイレクトしようとしますが、可能でない場合(ブラウザはHTTP_REFERRERヘッダーをブロックしています)、 :fallback_location
リダイレクトされ:fallback_location
ビューの使用
ルートを想定します。
resources :users, only: [:index]
コントローラー:
class UsersController < ApplicationController def index respond_to do |format| format.html { render } end end end
ビューapp/users/index.html.erb
がレンダリングされます。ビューが次の場合:
Hello <strong>World</strong>
出力は「Hello World 」というテキストのWebページになります。
別のビューをレンダリングする場合は、次のものを使用できます。
render "pages/home"
代わりにapp/views/pages/home.html.erb
ファイルが代わりに使用されます。
コントローラインスタンス変数を使用してビューに変数を渡すことができます:
class UsersController < ApplicationController def index @name = "john" respond_to do |format| format.html { render } end end end
そして、 app/views/users/index.html.erb
ファイルで@name
を使うことができます:
Hello <strong><%= @name %></strong>
そして出力は次のようになります: "こんにちはジョン "
レンダリング構文について重要な注意点がありますが、 render
構文を完全に省略することができます。省略すると、Railsはこれを仮定します。そう:
class UsersController < ApplicationController def index respond_to do |format| format.html { render } end end end
代わりに次のように書くことができます:
class UsersController < ApplicationController def index respond_to do |format| format.html end end end
Railsは、 app/views/users/index.html.erb
ファイルをレンダリングする必要があることを理解するのに十分スマートapp/views/users/index.html.erb
。
レコードが見つからない場合は404
例外または白いページを表示するのではなく、レコードから救助してください。
class ApplicationController < ActionController::Base
# ... your other stuff here
rescue_from ActiveRecord::RecordNotFound do |exception|
redirect_to root_path, 404, alert: 'Record not found'
end
end
基本的なRESTコントローラ
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
def index
@posts = Post.all
end
def show
end
def new
@post = Post.new
end
def edit
end
def create
@post = Post.new(post_params)
respond_to do |format|
if @post.save
format.html { redirect_to @post, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: @post }
else
format.html { render :new }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if @post.update(post_params)
format.html { redirect_to @post.company, notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: @post }
else
format.html { render :edit }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end
def destroy
@post.destroy
respond_to do |format|
format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_post
@post = Post.find(params[:id])
end
def post_params
params.require(:post).permit(:title, :body, :author)
end
end
例外のエラーページを表示する
単純な「申し訳ありませんが、何かが間違っていた」のではなく、意味のあるエラーをユーザに表示したい場合、Railsはこの目的のための素晴らしいユーティリティを持っています。
app/controllers/application_controller.rb
ファイルを開き、次のようなコードを見つけてください:
class ApplicationController < ActionController::Base protect_from_forgery with: :exception end
特定のエラーから回復するためにrescue_from
を追加できるようになりました。
class ApplicationController < ActionController::Base protect_from_forgery with: :exception rescue_from ActiveRecord::RecordNotFound, with: :record_not_found private def record_not_found render html: "Record <strong>not found</strong>", status: 404 end end
Exception
またはStandardError
から救助しないことが推奨されます。さもなければ、Railsはエラーの場合に役立つページを表示できません。
フィルタ
フィルタは、コントローラアクションの前、後または後に実行されるメソッドです。これらは継承されているため、 ApplicationController
に任意の値を設定すると、 ApplicationController
が受け取る要求ごとに実行されます。
フィルタ前
フィルタがコントローラの動作の前に実行され、要求を停止する(および/またはリダイレクトする)前に、一般的な使い方は、ユーザーがログインしているかどうかを確認することです。
class ApplicationController < ActionController::Base
before_action :authenticate_user!
def authenticate_user!
redirect_to some_path unless user_signed_in?
end
end
リクエストがコントローラのアクションに到達する前にフィルタがリクエストで実行される前。応答自体を返し、アクションを完全にバイパスすることができます。
beforeフィルタのその他の一般的な使用法は、リクエストを処理するために指定されたアクションへのアクセスを許可する前に、ユーザーの認証を検証することです。また、データベースからリソースをロードしたり、リソースのアクセス権をチェックしたり、他の状況でリダイレクトを管理したりするのにも使用されています。
フィルターの後
フィルターは「前」と似ていますが、アクションの実行後に実行されるので、送信しようとしている応答オブジェクトにアクセスできます。したがって、アクションが完了した後でフィルタが実行された直後です。それは応答を変更することができます。たいていの場合、後のフィルタで何かが行われると、アクション自体で実行できますが、一連のアクションを実行した後に実行するロジックがある場合は、後のフィルタが適切な場所ですそれ。
一般的に、私はロギングに使用されたフィルターの前後を見てきました。
フィルターの周り
フィルターの周りには、アクションが実行される前後に論理がある場合があります。それは、必要な場所でアクションに結びつくだけです。それはアクションに降伏する必要はなく、前のフィルターのように実行する必要はありません。
フィルタの周りは、ラックミドルウェアがどのように動作するかと同様に、降伏によって関連する動作を実行する責任があります。
前後のコールバックはアクションの実行をラップします。折り返しコールバックを2つの異なるスタイルで書くことができます。最初は、コールバックはコードの単一のチャンクです。そのコードは、アクションが実行される前に呼び出されます。コールバックコードがyieldを呼び出すと、アクションが実行されます。アクションが完了すると、コールバックコードは実行を継続します。したがって、yieldの前のコードはbeforeアクションのコールバックのようになり、yieldの後のコードはafterアクションのコールバックになります。コールバックコードがyieldを呼び出さない場合アクションは実行されません。これは、前のアクションコールバックにfalseを返すことと同じです。
aroundフィルタの例を次に示します。
around_filter :catch_exceptions
private
def catch_exceptions
begin
yield
rescue Exception => e
logger.debug "Caught exception! #{e.message}"
end
end
これは任意のアクションの例外をキャッチし、メッセージをログに記録します。例外処理、セットアップとティアダウン、その他の無数の場合にフィルタを使用することができます。
のみと例外
すべてのフィルタは、以下を使用して特定のアクションに適用できます:only
および:except
:
class ProductsController < ApplicationController
before_action :set_product, only: [:show, :edit, :update]
# ... controller actions
# Define your filters as controller private methods
private
def set_product
@product = Product.find(params[:id])
end
end
フィルターをスキップする
すべてのフィルタ(継承されたフィルタも)は、特定のアクションに対してスキップすることもできます。
class ApplicationController < ActionController::Base
before_action :authenticate_user!
def authenticate_user!
redirect_to some_path unless user_signed_in?
end
end
class HomeController < ApplicationController
skip_before_action :authenticate_user!, only: [:index]
def index
end
end
継承されているので、フィルタはnamespace
「親」コントローラで定義することもできnamespace
。たとえば、 admin
名前空間があり、 admin
者ユーザーだけがアクセスできるようにしたいとします。次のようなことができます:
# config/routes.rb
namespace :admin do
resources :products
end
# app/controllers/admin_controller.rb
class AdminController < ApplicationController
before_action :authenticate_admin_user!
private
def authenticate_admin_user!
redirect_to root_path unless current_user.admin?
end
end
# app/controllers/admin/products_controller.rb
class Admin::ProductsController < AdminController
# This controller will inherit :authenticate_admin_user! filter
end
Rails 4.xでは before_filter
をbefore_action
とbefore_action
することができますが、 before_filter
は現在Rails 5.0.0で非推奨であり、 5.1で削除されることに注意してください。
コントローラの生成
Railsはもちろん、コントローラー用の多くのジェネレーターを提供しています。
あなたのアプリケーションフォルダでこのコマンドを実行すると、新しいコントローラを生成することができます
rails generate controller NAME [action action] [options]
注意: rails g
エイリアスを使用して、 rails generate
を呼び出すこともできrails g
たとえば、 #index
アクションと#show
アクションを#show
してProduct
モデル用のコントローラを生成するには
rails generate controller products index show
これにより、指定した両方のアクションを持つコントローラがapp/controllers/products_controller.rb
に作成されます
class ProductsController < ApplicationController
def index
end
def show
end
end
また、コントローラのアクション用の2つのテンプレート( index.html.erb
とshow.html.erb
)を含むapp/views/
中にproducts
フォルダを作成します。 拡張子はテンプレートエンジンによって異なる可能性があるので注意してください。使用して「再slim
例えば、発電機が作成され、 index.html.slim
とshow.html.slim
)
さらに、アクションを指定した場合は、 routes
ファイルにも追加されます
# config/routes.rb
get 'products/show'
get 'products/index'
Railsはapp/helpers/products_helper.rb
ヘルパーファイルを作成し、 app/assets/javascripts/products.js
とapp/assets/stylesheets/products.css
のアセットファイルも作成しapp/assets/stylesheets/products.css
。ビューについてはジェネレータがGemfile
指定されたものに従ってこの動作を変更します。つまり、アプリケーションでCoffeescript
とSass
を使用している場合、コントローラジェネレータはproducts.coffee
とproducts.sass
products.coffee
しproducts.sass
。
最後に、Railsはコントローラ、ヘルパー、ビューのテストファイルを生成します。
Railsにそれらをスキップするように指示するためにこれらのものを作成したくない場合は、
--no-
または--skip
、このように:
rails generate controller products index show --no-assets --no-helper
そしてジェネレータはassets
とhelper
両方をスキップします
特定のnamespace
用のコントローラを作成する必要がある場合は、 NAME
前に追加しnamespace
。
rails generate controller admin/products
これで、コントローラはapp/controllers/admin/products_controller.rb
内に作成されます
Railsは、完全なRESTfulコントローラを生成することもできます。
rails generate scaffold_controller MODEL_NAME # available from Rails 4
rails generate scaffold_controller Product
Rescue:ActiveRecord :: RecordNotFound with redirect_to
エラーページを表示するのではなく、リダイレクトを使ってRecordNotFound例外を救済することができます:
class ApplicationController < ActionController::Base
# your other stuff
rescue_from ActiveRecord::RecordNotFound do |exception|
redirect_to root_path, 404, alert: I18n.t("errors.record_not_found")
end
end