Ruby on Rails
Controlador de acción
Buscar..
Introducción
Controlador de acción es la C en MVC. Una vez que el enrutador ha determinado qué controlador utilizar para una solicitud, el controlador es responsable de dar sentido a la solicitud y de producir la salida.
El controlador recibirá la solicitud, buscará o guardará datos de un modelo y usará una vista para crear resultados. Un controlador puede considerarse como un intermediario entre los modelos y las vistas. Hace que los datos del modelo estén disponibles para la vista para que puedan mostrarse al usuario, y guarda o actualiza los datos del usuario al modelo.
Salida JSON en lugar de 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
Además necesitarás la ruta:
resources :users, only: [:index]
Esto responderá de dos formas diferentes a las solicitudes de /users
:
- Si visita
/users
o/users.html
, mostrará una página html con el contenidoHello World
- Si visita
/users.json
, mostrará un objeto JSON que contiene:
[ { "name": "foo", "email": "[email protected]" } ]
Puede omitir format.html { render inline: "Hello World" }
si quiere asegurarse de que su ruta solo responda a las solicitudes JSON.
Controladores (básicos)
class UsersController < ApplicationController def index respond_to do |format| format.html { render html: "Hello World" } end end end
Este es un controlador básico, con la adición de la siguiente ruta (en route.rb):
resources :users, only: [:index]
Mostrará el mensaje de Hello World
en una página web cuando acceda a la URL /users
Parámetros
Los controladores tienen acceso a los parámetros HTTP (es posible que los conozcan como ?name=foo
en las URL, ¡pero Ruby on Rails también maneja diferentes formatos!) Y generan diferentes respuestas basadas en ellos. No hay una manera de distinguir entre los parámetros GET y POST, pero no debes hacer eso en ningún caso.
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
Como de costumbre nuestra ruta:
resources :users, only: [:index]
Acceda a la URL /users?name=john
y la salida será Hello John
, access /users?name=whatever
y la salida será Hello someone
Parámetros de filtrado (Básico)
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
Puede permitir (o rechazar) algunos parámetros para que solo pase lo que usted desea y no tenga sorpresas desagradables, como las opciones de configuración del usuario que no deben cambiarse.
Visitar /users?name=john&sentence=developer
mostrará el /users?name=john&sentence=developer
Hello john developer
, sin embargo visitando /users?name=smith&sentence=spy
mostrará Hello smith
, porque :sentence
solo está permitida cuando accede como john
Redirigiendo
Asumiendo la ruta:
resources :users, only: [:index]
Puede redirigir a una URL diferente usando:
class UsersController def index redirect_to "http://stackoverflow.com/" end end
Puede volver a la página anterior que el usuario visitó usando:
redirect_to :back
Tenga en cuenta que en Rails 5 la sintaxis para redirigir hacia atrás es diferente:
redirect_back fallback_location: "http://stackoverflow.com/"
El cual intentará redirigir a la página anterior y en caso de que no sea posible (el navegador está bloqueando el encabezado HTTP_REFERRER), redirigirá a :fallback_location
Usando vistas
Asumiendo la ruta:
resources :users, only: [:index]
Y el controlador:
class UsersController < ApplicationController def index respond_to do |format| format.html { render } end end end
La vista de la app/users/index.html.erb
será renderizada. Si la vista es:
Hello <strong>World</strong>
La salida será una página web con el texto: "Hola mundo ".
Si quieres renderizar una vista diferente, puedes usar:
render "pages/home"
Y el archivo app/views/pages/home.html.erb
se usará en su lugar.
Puede pasar variables a vistas usando variables de instancia de controlador:
class UsersController < ApplicationController def index @name = "john" respond_to do |format| format.html { render } end end end
Y en el archivo app/views/users/index.html.erb
puede usar @name
:
Hello <strong><%= @name %></strong>
Y la salida será: "Hola John ".
Una nota importante sobre la sintaxis de procesamiento, puede omitir completamente la sintaxis de render
, Rails asume que si la omite. Asi que:
class UsersController < ApplicationController def index respond_to do |format| format.html { render } end end end
Se puede escribir en su lugar como:
class UsersController < ApplicationController def index respond_to do |format| format.html end end end
Rails es lo suficientemente inteligente como para darse cuenta de que debe representar el archivo app/views/users/index.html.erb
.
404 cuando no se encuentra el registro
Rescate del error de registro no encontrado en lugar de mostrar una excepción o una página en blanco:
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
Controlador REST básico
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
Mostrar páginas de error para excepciones
Si desea mostrar a sus usuarios errores significativos en lugar de un simple "perdón, algo salió mal", Rails tiene una buena utilidad para este propósito.
Abra el archivo app/controllers/application_controller.rb
y debería encontrar algo como esto:
class ApplicationController < ActionController::Base protect_from_forgery with: :exception end
Ahora podemos agregar un rescue_from
para recuperarse de errores específicos:
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
Se recomienda no rescatar de Exception
o StandardError
contrario Rails no podrá mostrar páginas útiles en caso de errores.
Filtros
Los filtros son métodos que se ejecutan "antes", "después" o "alrededor" de una acción del controlador. Se heredan, por lo que si establece alguno en su ApplicationController
, se ejecutarán para cada solicitud que reciba su aplicación.
Antes del filtro
Antes de que los filtros se ejecuten antes de la acción del controlador y puedan detener la solicitud (y / o redirigir). Un uso común es verificar si un usuario ha iniciado sesión:
class ApplicationController < ActionController::Base
before_action :authenticate_user!
def authenticate_user!
redirect_to some_path unless user_signed_in?
end
end
Antes de que se ejecuten los filtros en las solicitudes antes de que la solicitud llegue a la acción del controlador. Puede devolver una respuesta por sí misma y omitir completamente la acción.
Otros usos comunes de los filtros anteriores son la validación de la autenticación de un usuario antes de otorgarles acceso a la acción designada para manejar su solicitud. También los he visto usar para cargar un recurso de la base de datos, verificar permisos en un recurso o administrar redirecciones en otras circunstancias.
Después del filtro
Los filtros posteriores son similares a los "anteriores", pero a medida que se ejecutan después de la ejecución de la acción, tienen acceso al objeto de respuesta que está a punto de enviarse. En resumen, después de que se ejecutan los filtros después de que se completa la acción. Puede modificar la respuesta. La mayoría de las veces, si se hace algo en un filtro posterior, se puede hacer en la acción misma, pero si hay algo de lógica que ejecutar después de ejecutar cualquiera de un conjunto de acciones, entonces un filtro posterior es un buen lugar para hacer. eso.
En general, he visto después y alrededor de los filtros utilizados para el registro.
Alrededor del filtro
Alrededor de los filtros puede haber lógica antes y después de la acción que se está ejecutando. Simplemente cede a la acción en cualquier lugar que sea necesario. Tenga en cuenta que no es necesario ceder a la acción y puede ejecutarse sin hacerlo como un filtro anterior.
Alrededor de los filtros son responsables de ejecutar sus acciones asociadas mediante el rendimiento, similar a cómo funcionan los middleware de Rack.
Alrededor de las devoluciones de llamada envuelve la ejecución de acciones. Puede escribir una vuelta de llamada en torno a dos estilos diferentes. En el primero, la devolución de llamada es una sola porción de código. Ese código se llama antes de que se ejecute la acción. Si el código de devolución de llamada invoca el rendimiento, la acción se ejecuta. Cuando la acción se completa, el código de devolución de llamada continúa ejecutándose. Por lo tanto, el código anterior al rendimiento es como una devolución de llamada de acción anterior y el código posterior al rendimiento es la devolución de llamada posterior a la acción. Si el código de devolución de llamada nunca invoca el rendimiento. la acción no se ejecuta; esto es lo mismo que tener un retorno de devolución de llamada de acción anterior falso.
Aquí hay un ejemplo del filtro de alrededor:
around_filter :catch_exceptions
private
def catch_exceptions
begin
yield
rescue Exception => e
logger.debug "Caught exception! #{e.message}"
end
end
Esto detectará la excepción de cualquier acción y pondrá el mensaje en su registro. Puede usar alrededor de los filtros para el manejo de excepciones, la configuración y el desmontaje, y muchos otros casos.
Solo y Excepto
Todos los filtros se pueden aplicar a acciones específicas, utilizando :only
y :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
Filtro de salto
También se pueden omitir todos los filtros (también los heredados) para algunas acciones específicas:
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
A medida que se heredan, los filtros también se pueden definir en un controlador "primario" de namespace
. Digamos, por ejemplo, que tiene un espacio de nombres de admin
y, por supuesto, desea que solo los usuarios administradores puedan acceder a él. Podrías hacer algo como esto:
# 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
Tenga en cuenta que en Rails 4.x puede usar before_filter
junto con before_action
, pero before_filter
está actualmente en desuso en Rails 5.0.0 y se eliminará en 5.1 .
Generando un controlador
Rails proporciona muchos generadores, también para los controladores, por supuesto.
Puede generar un nuevo controlador ejecutando este comando en su carpeta de aplicaciones
rails generate controller NAME [action action] [options]
Nota: también puede usar rails g
alias para invocar rails generate
Por ejemplo, para generar un controlador para un modelo de Product
, con las acciones #index
y #show
que ejecutaría
rails generate controller products index show
Esto creará el controlador en app/controllers/products_controller.rb
, con las dos acciones que especificó
class ProductsController < ApplicationController
def index
end
def show
end
end
También creará una carpeta de products
dentro de app/views/
, que contiene las dos plantillas para las acciones de su controlador (es decir, index.html.erb
y show.html.erb
, tenga en cuenta que la extensión puede variar según el motor de su plantilla, por lo que si show.html.slim
usando slim
, por ejemplo, el generador creará index.html.slim
y show.html.slim
)
Además, si especificó alguna acción, también se agregarán a su archivo de routes
# config/routes.rb
get 'products/show'
get 'products/index'
Rails crea un archivo de ayuda para usted, en app/helpers/products_helper.rb
, y también los archivos de activos en app/assets/javascripts/products.js
y app/assets/stylesheets/products.css
. En cuanto a las vistas, el generador cambia este comportamiento de acuerdo con lo que se especifica en su Gemfile
: es decir, si está utilizando Coffeescript
y Sass
en su aplicación, el generador del controlador generará products.coffee
y products.sass
.
Por último, pero no menos importante, Rails también genera archivos de prueba para su controlador, su ayudante y sus vistas.
Si no desea que se cree ninguno de estos, puede decirle a Rails que los omita, simplemente anteponga cualquier opción con
--no-
o --skip
, así:
rails generate controller products index show --no-assets --no-helper
Y el generador saltará tanto los assets
como el helper
Si necesita crear un controlador para un namespace
específico, agréguelo delante de NAME
:
rails generate controller admin/products
Esto creará su controlador dentro de app/controllers/admin/products_controller.rb
Rails también puede generar un controlador RESTful completo para usted:
rails generate scaffold_controller MODEL_NAME # available from Rails 4
rails generate scaffold_controller Product
Rescatando ActiveRecord :: RecordNotFound con redirect_to
Puede rescatar una excepción RecordNotFound con una redirección en lugar de mostrar una página de error:
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