为所有成员路由设置之前的操作?

时间:2014-02-10 22:51:58

标签: ruby-on-rails actioncontroller

使用Rails 4时,我注意到它定义了before_action过滤器set_[model],该行为showeditupdatedestroy

它实际上非常有用,但我没有意识到没有将它用于所有成员行动。毕竟,如果您正在使用成员操作,那么您希望对该成员执行操作,因此您需要在某个时刻从数据库中恢复它。

请注意,通过成员操作,我还表示routes.rb块中members上配置的操作。

是否有直接的方法来执行此操作,而无需列出before_action过滤器上的所有成员操作?

编辑:为了澄清,重点是使用一些rails magic获取所有成员路由并生成将在:only中传递的数组。所以我可以做类似

的事情
before_action set_model only: all_member_routes

其中all_member_routes是一段代码,它返回我模型的所有成员路由。

甚至更好,

before_action set_model, only_member_actions: true

2 个答案:

答案 0 :(得分:6)

showeditupdatedestroy操作正是所有成员操作。他们是唯一需要找到模型的人。

如果您有自己的成员操作,那么您必须自己将其添加到列表中。

before_action :set_item, only: [:edit, ..., :my_member_action]

或者,您可以使用:except选项排除所有不需要它的集合操作:

before_action :set_item, except: [:index, :create]

这样,如果添加其他成员操作,则无需进行任何更改。 就个人而言,我更喜欢明确并使用:only

我很确定没有更简单的方法,你无法自动检测所有成员行为。


修改

我真的不认为你应该这样做但是......

您可以使用controller_name方法访问控制器的名称。

获取与控制器相关的路线:

routes = Rails.application.routes.routes.select { |r| r.defaults[:controller] == controller_name }

然后,我认为查看路由是否为成员路由的最佳方法是@parts数组包含:id。也许你可以找到一种更健壮的方式。

所以我会这样做:

routes.select { |r| r.parts.include?(:id) }.map { |r| r.defaults[:action] }.map &:to_sym

那会给你:[:show, :preview, :my_challenges]

 resources :users, only: [:index, :show], controller: 'accounts/users' do
   member do
     get :preview
     get :my_challenges
   end
 end

class ApplicationController < ActionController::Base 

    def member_routes
        Rails.application.routes.routes
            .select { |r| r.defaults[:controller] == controller_name && r.parts.include?(:id) }
            .map { |r| r.defaults[:action] }
            .map(&:to_sym)
    end

end

class UsersController < ApplicationController
    before_action set_model, only: member_routes
end

答案 1 :(得分:3)

如果您要求before_action没有:only:except选项,它将适用于所有成员操作:

class ApplicationController < ActionController::Base
  before_action :require_login

  private

  def require_login
    unless logged_in?
      flash[:error] = "You must be logged in to access this section"
      redirect_to new_login_url # halts request cycle
    end
  end
end

在这种特殊情况下,它需要从所有控制器上的所有操作进行登录,因为控制器将从ApplicationController继承。

如果您需要,可以跳过before_action(例如,如果您想要require_login进入系统或login,则需要跳过sign up) :

class LoginsController < ApplicationController
  skip_before_action :require_login, only: [:new, :create]
end

来源:Rails Guides


所以,在你的特定情况下:

你可以有一个常用的UserController:

class UserController < ApplicationController
  def index
  end


  ...
  /* you define here `index`, `create`, `update`, ... */
  def destroy
    ...
  end
end

您可以拥有一个单独的控制器来执行您的所有成员操作:

class UserCustomController < ApplicationController
  before_action :set_model

  def profile
    ...
  end

  def preview
  end   

  def custom_member_action
  end

  ...
  /* all your member actions */
end

这实际上比拥有大量方法的单个控制器更好。