サーチ…


前書き

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_filterbefore_actionbefore_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.erbshow.html.erb )を含むapp/views/中にproductsフォルダを作成します。 拡張子はテンプレートエンジンによって異なる可能性があるので注意してください。使用して「再slim例えば、発電機が作成され、 index.html.slimshow.html.slim

さらに、アクションを指定した場合は、 routesファイルにも追加されます

# config/routes.rb
get 'products/show'
get 'products/index'

Railsはapp/helpers/products_helper.rbヘルパーファイルを作成し、 app/assets/javascripts/products.jsapp/assets/stylesheets/products.cssのアセットファイルも作成しapp/assets/stylesheets/products.css 。ビューについてはジェネレータがGemfile指定されたものに従ってこの動作を変更します。つまり、アプリケーションでCoffeescriptSassを使用している場合、コントローラジェネレータはproducts.coffeeproducts.sass products.coffeeproducts.sass

最後に、Railsはコントローラ、ヘルパー、ビューのテストファイルを生成します。

Railsにそれらをスキップするように指示するためにこれらのものを作成したくない場合は、

--no-または--skip 、このように:

rails generate controller products index show --no-assets --no-helper

そしてジェネレータはassetshelper両方をスキップします

特定の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


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow