Suche…


Einführung

Action Controller ist das C in MVC. Nachdem der Router festgelegt hat, welcher Controller für eine Anfrage verwendet werden soll, ist der Controller dafür verantwortlich, die Anfrage zu verstehen und die Ausgabe zu erzeugen.

Der Controller empfängt die Anforderung, holt oder speichert Daten von einem Modell und verwendet eine Ansicht, um eine Ausgabe zu erstellen. Ein Controller kann als Zwischenhändler zwischen Modellen und Ansichten betrachtet werden. Es macht die Modelldaten für die Ansicht verfügbar, sodass sie dem Benutzer angezeigt werden kann, und es speichert oder aktualisiert Benutzerdaten im Modell.

Ausgabe von JSON anstelle von HTML

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

Zusätzlich benötigen Sie die Route:

resources :users, only: [:index]

Dies wird auf zwei verschiedene Arten auf Anfragen an /users reagieren:

  • Wenn Sie /users oder /users.html , wird eine HTML-Seite mit dem Inhalt Hello World /users.html
  • Wenn Sie /users.json besuchen, wird ein JSON-Objekt /users.json , das /users.json enthält:
[
  {
    "name": "foo",
    "email": "[email protected]"
  }
]

Wenn Sie sicherstellen möchten, dass Ihre Route nur auf JSON-Anforderungen antwortet, können Sie format.html { render inline: "Hello World" } weglassen .

Steuerungen (Basic)

class UsersController < ApplicationController
  def index
    respond_to do |format|
      format.html { render html: "Hello World" }
    end
  end
end

Dies ist ein Basiscontroller mit dem Hinzufügen der folgenden Route (in routes.rb):

resources :users, only: [:index]

Zeigt die Hello World Nachricht auf einer Webseite an, wenn Sie auf die URL /users zugreifen

Parameter

Controller haben Zugriff auf HTTP-Parameter (Sie kennen sie vielleicht als ?name=foo in URLs, aber Ruby on Rails verarbeiten auch unterschiedliche Formate!) Und geben darauf basierend unterschiedliche Antworten aus. Es gibt keine Möglichkeit, zwischen GET- und POST-Parametern zu unterscheiden, aber Sie sollten dies auf keinen Fall tun.

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

Wie üblich unsere Route:

resources :users, only: [:index]

Greifen Sie auf die URL /users?name=john und die Ausgabe wird Hello John , der Zugriff auf /users?name=whatever und die Ausgabe wird Hello someone

Filterparameter (Basic)

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

Sie können einige Parameter zulassen (oder ablehnen), so dass nur das, was Sie möchten , durchgeht und Sie keine bösen Überraschungen wie Benutzereinstellungen haben, die nicht geändert werden sollen.

Besuch /users?name=john&sentence=developer zeigt Hello john developer , aber Besuch /users?name=smith&sentence=spy zeigt nur Hello smith , weil :sentence nur zulässig ist, wenn Sie als john zugreifen

Umleitung

Annahme der Route:

resources :users, only: [:index]

Sie können zu einer anderen URL umleiten mit:

class UsersController
  def index
    redirect_to "http://stackoverflow.com/"
  end
end

Sie können zur vorherigen Seite zurückkehren, die der Benutzer besucht hat:

redirect_to :back

Beachten Sie, dass in Rails 5 die Syntax für das Zurückleiten anders ist:

redirect_back fallback_location: "http://stackoverflow.com/"

Dadurch wird versucht, auf die vorherige Seite umzuleiten, und falls dies nicht möglich ist (der Browser blockiert den HTTP_REFERRER-Header), wird es weitergeleitet an :fallback_location

Ansichten verwenden

Annahme der Route:

resources :users, only: [:index]

Und der Controller:

class UsersController < ApplicationController
  def index
    respond_to do |format|
      format.html { render }
    end
  end
end

Die Ansichtsanwendung app/users/index.html.erb wird gerendert. Wenn die Ansicht ist:

Hello <strong>World</strong>

Die Ausgabe wird eine Webseite mit dem Text "Hello World " sein.

Wenn Sie eine andere Ansicht rendern möchten, können Sie Folgendes verwenden:

render "pages/home"

app/views/pages/home.html.erb wird die Datei app/views/pages/home.html.erb verwendet.

Sie können Variablen mithilfe von Controller-Instanzvariablen an Ansichten übergeben:

class UsersController < ApplicationController
  def index
    @name = "john"

    respond_to do |format|
      format.html { render }
    end
  end
end

Und in der Datei app/views/users/index.html.erb Sie @name :

Hello <strong><%= @name %></strong>

Und die Ausgabe wird sein: "Hallo John "

Ein wichtiger Hinweis rund um die Render-Syntax. Sie können die render Syntax vollständig weglassen. So:

class UsersController < ApplicationController
  def index
    respond_to do |format|
      format.html { render }
    end
  end
end

Kann stattdessen geschrieben werden als:

class UsersController < ApplicationController
  def index
    respond_to do |format|
      format.html
    end
  end
end

Rails ist intelligent genug, um herauszufinden, dass es die Datei app/views/users/index.html.erb .

404 wenn Datensatz nicht gefunden wurde

Fehler beim Aufheben des Datensatzes nicht gefunden, anstatt eine Ausnahme oder eine weiße Seite anzuzeigen:

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

Grundlegender REST-Controller

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

Fehlerseiten für Ausnahmen anzeigen

Wenn Sie Ihren Benutzern sinnvolle Fehler anzeigen möchten, anstatt nur "Entschuldigung, es ist ein Fehler aufgetreten", bietet Rails ein nützliches Hilfsprogramm.

Öffnen Sie die Datei app/controllers/application_controller.rb und Sie sollten etwa Folgendes finden:

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
end

Wir können jetzt ein rescue_from hinzufügen, um bestimmte Fehler zu beheben:

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

Es wird empfohlen, nicht vor Exception oder StandardError zu retten, da Rails im Fehlerfall keine hilfreichen Seiten anzeigen kann.

Filter

Filter sind Methoden, die "vor", "nach" oder "um" eine Controller-Aktion ausgeführt werden. Sie werden vererbt. Wenn Sie also in Ihrem ApplicationController Einstellung festlegen, werden sie für jede Anforderung ausgeführt, die Ihre Anwendung empfängt.

Vor dem Filter

Bevor Filter vor der Controller-Aktion ausgeführt werden, kann die Anforderung (und / oder die Weiterleitung) angehalten werden. Häufig wird überprüft, ob ein Benutzer angemeldet ist:

class ApplicationController < ActionController::Base
  before_action :authenticate_user!

  def authenticate_user!
    redirect_to some_path unless user_signed_in?
  end
end

Vor dem Ausführen von Filtern für Anforderungen, bevor die Anforderung die Aktion des Controllers erhält. Es kann eine Antwort selbst zurückgeben und die Aktion vollständig umgehen.

Eine weitere häufige Anwendung von before-Filtern ist das Überprüfen der Authentifizierung eines Benutzers, bevor ihm der Zugriff auf die Aktion gewährt wird, die für die Bearbeitung seiner Anfrage festgelegt wurde. Ich habe auch gesehen, wie sie zum Laden einer Ressource aus der Datenbank, zum Überprüfen von Berechtigungen für eine Ressource oder zum Verwalten von Weiterleitungen unter anderen Umständen verwendet wurden.

Nach dem Filter

Nach Filtern ähneln die Filter "vor", aber wenn sie nach dem Aktionslauf ausgeführt werden, haben sie Zugriff auf das Antwortobjekt, das gesendet werden soll. Also kurz nachdem Filter ausgeführt wurden, nachdem die Aktion abgeschlossen ist. Es kann die Antwort ändern. Wenn etwas in einem Nachfilter ausgeführt wird, kann dies meistens in der Aktion selbst ausgeführt werden. Wenn jedoch nach dem Ausführen einer Reihe von Aktionen eine Logik ausgeführt werden muss, ist ein Nachfilter ein guter Ort es.

Im Allgemeinen habe ich nach und um Filter gesehen, die für die Protokollierung verwendet werden.

Um den Filter herum

Um Filter herum kann es vor und nach der ausgeführten Aktion Logik geben. Es gibt einfach die Handlung an dem Ort, wo es notwendig ist. Beachten Sie, dass es der Aktion nicht nachgeben muss und möglicherweise wie ein vorheriger Filter ausgeführt wird.

Around-Filter sind für die Ausführung ihrer zugehörigen Aktionen verantwortlich, ähnlich wie Rack-Middlewares.

Callbacks umschließen die Ausführung von Aktionen. Sie können einen Rückruf in zwei verschiedenen Stilen schreiben. Im ersten Fall ist der Rückruf ein einzelner Code. Dieser Code wird aufgerufen, bevor die Aktion ausgeführt wird. Wenn der Rückrufcode die Fließmenge aufruft, wird die Aktion ausgeführt. Wenn die Aktion abgeschlossen ist, wird der Callback-Code weiter ausgeführt. Daher ist der Code vor der Rendite wie ein Callback vor der Aktion und der Code nach der Rendite ist der Callback nach der Aktion. Wenn der Rückrufcode niemals ertrag aufruft. Die Aktion wird nicht ausgeführt. Dies ist dasselbe, als wenn ein Callback vor der Aktion false zurückgibt.

Hier ist ein Beispiel für den Around-Filter:

around_filter :catch_exceptions
 
private
  def catch_exceptions
    begin
      yield
    rescue Exception => e 
      logger.debug "Caught exception! #{e.message}"
    end
  end

Dies fängt die Ausnahme einer Aktion ab und fügt die Nachricht in Ihr Protokoll ein. Sie können Filter für die Ausnahmebehandlung, das Einrichten und Abbauen sowie eine Vielzahl anderer Fälle verwenden.

Nur und außer

Alle Filter können auf bestimmte Aktionen angewendet werden :only und :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

Filter überspringen

Alle Filter (auch geerbte Filter) können für bestimmte Aktionen auch übersprungen werden:

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

Da sie geerbt sind, können Filter auch in einem übergeordneten Controller für namespace definiert werden. Angenommen, Sie haben einen admin Namespace, und Sie möchten natürlich nur Admin-Benutzer darauf zugreifen können. Sie könnten so etwas tun:

# 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

before_filter Sie, dass Sie in Rails 4.x before_filter zusammen mit before_action , aber before_filter ist derzeit in Rails 5.0.0 veraltet und wird in 5.1 entfernt .

Controller generieren

Rails bietet viele Generatoren, natürlich auch für Controller.

Sie können einen neuen Controller generieren, indem Sie diesen Befehl in Ihrem App-Ordner ausführen

rails generate controller NAME [action action] [options]

Hinweis: Sie können auch rails g Alias ​​verwenden, um das rails generate aufzurufen

Um beispielsweise einen Controller für ein Product zu generieren, #index #show Aktionen #index und #show ausführen

rails generate controller products index show

Dadurch wird der Controller in app/controllers/products_controller.rb mit den von Ihnen angegebenen Aktionen erstellt

class ProductsController < ApplicationController
  def index
  end

  def show
  end
end

Es wird auch ein erstellen products Ordner in app/views/ , die beiden Vorlagen für Ihre Controller Aktionen enthält (dh index.html.erb und show.html.erb , beachten Sie, dass die Erweiterung entsprechend Ihre Template - Engine kann variieren, so dass , wenn Sie Verwenden Sie slim , zum Beispiel erzeugt der Generator index.html.slim und show.html.slim

Wenn Sie Aktionen angegeben haben, werden diese auch Ihrer routes hinzugefügt

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

Rails erstellt für Sie eine Hilfedatei in app/helpers/products_helper.rb sowie die Bestandsdateien in app/assets/javascripts/products.js und app/assets/stylesheets/products.css . In Gemfile auf Ansichten ändert der Generator dieses Verhalten entsprechend den Angaben in Ihrer Gemfile : Wenn Sie in Ihrer Anwendung Coffeescript und Sass verwenden, Coffeescript der Controller-Generator stattdessen products.coffee und products.sass .

Zu guter Letzt erzeugt Rails auch Testdateien für Ihren Controller, Ihren Helfer und Ihre Ansichten.

Wenn Sie nicht möchten, dass eines davon erstellt wird, können Sie Rails mitteilen, es zu überspringen

--no- oder --skip wie --skip :

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

Und der Generator überspringt sowohl assets als auch helper

Wenn Sie einen Controller für einen bestimmten namespace erstellen müssen, fügen Sie ihn vor NAME :

rails generate controller admin/products

Dadurch wird Ihre Steuerung in app/controllers/admin/products_controller.rb

Rails kann auch einen kompletten RESTful-Controller für Sie generieren:

rails generate scaffold_controller MODEL_NAME # available from Rails 4
rails generate scaffold_controller Product

ActiveRecord :: RecordNotFound mit redirect_to retten

Sie können eine RecordNotFound-Ausnahme mit einer Weiterleitung retten, anstatt eine Fehlerseite anzuzeigen:

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
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow