简体   繁体   English

使用自定义操作的Rails 5路由资源

[英]Rails 5 routing resources using custom actions

About routing, If I do something like this: 关于路由,如果我做这样的事情:

resources :students
resources :teachers

I will get something like: 我会得到类似:

students GET /students(.:format) students#index 学生GET /学生(。:format)学生#index
... ...
teachers GET /teachers(.:format) teachers#index 教师GET /teachers(.:format)教师#index
... ...

Changing to: 更改为:

resources :students, controller: :users
resources :teachers, controller: :users

will give me: 会给我:

students GET /students(.:format) users#index 学生GET /students(.:format)users#index
teachers GET /teachers(.:format) users#index 教师GET /teachers(.:format)users#index

Note that now, both resources are using the same controller Users and the same action index . 请注意,现在,两个资源都使用相同的控制器Users和相同的操作index But what I need, instead of using the same index action, is the students resource to use actions prefixed by students like students_index and teachers resources prefixed by teachers like teacher_index . 但是,我需要的不是使用相同的index动作,而是使用students资源来使用以students为前缀的动作(如students_index和以teachers为前缀的teachers资源(如teacher_index

In other words, I want bin/rails routes to give me the following output: 换句话说,我希望bin/rails routes能够提供以下输出:

students GET /students(.:format) users#students_index 学生GET /students(.:format)users#students_index
teachers GET /teachers(.:format) users#teachers_index 教师GET /teachers(.:format)users#teachers_index

I know that I can do the same with: 我知道我可以使用以下方法进行操作:

get 'students', to: 'users#students_index'

But there is a way to do the same with resources? 但是有一种方法可以对资源进行处理吗?

I don't think there's a way to do that with resources helper. 我认为没有办法使用资源助手来做到这一点。 What you could do (if it's only the index action you wanna override) is add an except, like this: 您可以执行的操作(如果仅是您要覆盖的索引操作)是添加一个例外,如下所示:

resources :students, controller: :users, except: [:index]
resources :teachers, controller: :users, except: [:index]

then, as you already suggested, do the individuals index actions like that: 然后,正如您已经建议的那样,个人对此类操作进行索引:

get 'students', to: 'users#students_index', as: :student
get 'teachers', to: 'users#teachers_index', as: :teacher

Or you could reconsider the structure of your controllers... Good luck! 或者您可以重新考虑控制器的结构...祝您好运!

There is a far better way to do this as you might have surmised - inheritance. 有一种更好的方法可以做到这一点,因为您可能已经猜到了-继承。

# app/controllers/users_controller.rb
class UsersController < ApplicationController

  delegate :singular, :plural, :param_key, to: :model_name

  before_action :set_resource, only: [:show, :edit, :update, :destroy]
  before_action :set_resources, only: [:index]

  def initialize
    @model_name = resource_class.model_name
    super
  end

  def show
  end

  def index
  end

  def new
    @resource = resource_class.new
    set_resource
  end

  def create
    @resource = resource_class.new(permitted_attributes)

    if @resource.save
      redirect_to @resource
    else
      set_resource
      render :new
    end
  end

  def edit
  end

  def update
    if @resource.update(permitted_attributes)
      redirect_to @resource
    else
      set_resource
      render :edit
    end
  end

  def destroy
    @resource.destroy
    redirect_to action: "index"
  end

  # ...

  private

  # Deduces the class of the model based on the controller name
  # TeachersController would try to resolve Teacher for example.
  def resource_class
    @resource_class ||= controller_name.classify.constantize
  end 

  # will set @resource as well as @teacher or @student
  def set_resource
    @resource ||= resource_class.find(params[:id])
    instance_variable_set("@#{singular}", @resource)
  end

  # will set @resources as well as @teachers or @students
  def set_resources
    @resources ||= resource_class.all
    instance_variable_set("@#{plural}", @resources)
  end

  def permitted_attributes
    params.require(param_key).permit(:a, :b, :c)
  end
end

# app/controllers/teachers_controller.rb
class TeachersController < UsersController
end

# app/controllers/students_controller.rb
class StudentsController < UsersController
end

# routes.rb
resources :students
resources :teachers

This lets you follow the regular Rails convention over configuration approach when it comes to naming actions and views. 在命名动作和视图时,这使您可以遵循常规的Rails约定而不是配置方法。

The UsersController base class uses quite a bit of magic through ActiveModel::Naming both to figure out the model class and stuff like what to name the instance variables and the params keys. UsersController基类通过ActiveModel :: Naming运用了很多魔术来找出模型类和诸如命名实例变量和params键之类的东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM