Ruby on Rails
ActionController
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 InhaltHello 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