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 contenido Hello 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


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow