【问题标题】:Ruby on Rails - pundit - unknown action for controllerRuby on Rails - 权威人士 - 控制器的未知操作
【发布时间】:2018-07-28 18:24:54
【问题描述】:

这个问题指的是this具体问题。

我使用 pundit 作为我的授权 gem,我希望用户 X 只能下载属于用户 X 的用户信息。现在我有 http://localhost:3000/download.csv 作为我的链接来接收用户信息。但是如果我登录到另一个用户,例如 user/2,我仍然可以输入 url 并下载 user/3 数据。

我现在拥有的:

user_policy.rb

class UserPolicy < ApplicationPolicy

  def profile?
    true
  end

  def download?

  end

  private

  def user_or_admin
    user.id == record.id || user.admin?
  end


end

application_policy.rb

class ApplicationPolicy
  attr_reader :user, :record

  def initialize(user, record)
    @user = user
    @record = record
  end

  def index?
    false
  end

  def show?
    scope.where(:id => record.id).exists?
  end

  def create?
    create?
  end

  def new?
    create?
  end

  def update?
    false
  end

  def edit?
    update?
  end

  def destroy?
    false
  end

  class Scope
    attr_reader :user, :scope

    def initialize(user, scope)
      @user = user
      @scope = scope
    end

    def resolve
      scope.all
    end
  end
end

这是我的 user_controller.rb # 这不是 users_controller,那是不同的视图

    class UserController < ApplicationController
  prepend_view_path(File.join(Rails.root, 'app/views/user/'))


  layout 'application'


  def index

  end

  def billing
  end

  def plan
  end

  def profile
    @user = User.find(params[:id])
    @user_posts = @user.posts.order('created_at DESC')
  end
end

def download
  @user = User.find(params[:id])

  respond_to do |format|
    format.html
    format.csv { send_data @user.csv, filename: "userinfo-#{Date.today}.csv" }
  end
end

  def support
    @user = User.find(params[:id])
    @user_posts = @user.posts.order('created_at DESC')
  end

  def notifications
  end

  def show
    @user = User.find(params[:id])
    @posts = current_user.posts.order('created_at DESC')
    @user_posts = @user.posts.order('created_at DESC')
  end

更新:按照建议,我尝试在我的 user_controller 中实现新的下载操作,并尝试在我的视图中使用此代码:

<p><%= link_to("Export data as CSV", download_path(@user, format: :csv), { :controller => :user, :action => :download }, class: "btn btn-success") %></p> 

但这会引发以下错误:

接收未知操作 - 找不到 UserController 的操作“下载”

routes.rb

        Rails.application.routes.draw do

  get 'legal/privacy'

  get :datenschutz, to: 'legal#terms_of_service'


  devise_for :users, path_names: { sign_in: 'login', sign_out: 'logout', sign_up: 'registrieren', edit: 'bearbeiten' }, :controllers => { registrations: 'registrations' }

  get '/users/mitteilungen/:id' => 'user#notifications'
  get '/users/:id/artikel/', :to => 'user#support', :as => :artikel
  get '/users/plan' => 'user#plan'
  get '/users/billing' => 'user#billing'
  get '/users/:id', :to => 'user#profile', :as => :user
  get 'download', :to => 'user#download', :controller => :user, action: :download, :as => :download


  resources :posts, path: :news do
    resources :comments, path: :kommentare do
    end
  end


  devise_scope :user do
    resources :posts, path: :news do
      resources :comments do

      end
    end
  end
  root to: "posts#index", as: :root

end

【问题讨论】:

  • 您可以将 csv 下载分离到另一个控制器操作/路由(类似于 download),然后使用策略中的 download? 方法从 profile 显示单独授权。
  • 我在用户控制器中创建了一个下载操作,我如何告诉我的 link_to 使用它?

    :user, :action => :download }, class: "btn btn-success" ) %>

    似乎不起作用
  • 您必须创建一个指向您的下载操作的自定义路由。如果你坚持下去,我会写一个答案。
  • 我创建了以下路由 get 'download', :to => 'user#download',但是单击按钮后,我得到了 UserController 的操作 'download' could not be found for UserController。另外我必须删除 class 参数,因为我只能允许 3 个参数,我将如何解决这个问题?感谢您帮助我!
  • 请发布您的 routes.rb

标签: ruby-on-rails pundit


【解决方案1】:

你的条件不对@user.id = user.id

user@user。我想你的意思是user.id = record.id

record 是您正在授权的实例,例如:

def show
  @user = User.find(params[:id])
  authorize @user
  ...
end

authorize @user 基本上是:UserPolicy.new(@user, current_user).show? 的快捷方式

顺便说一句,我不确定,但我认为您可以放心地省略 .id: user == record

UPD。 我重新阅读了您的政策。 ApplicationPolicy 通常如下所示:

class ApplicationPolicy
  attr_reader :user, :record

  def initialize(user, record)
    @user = user
    @record = record
  end
end

你重写了构造函数。为什么?让它保持 Pundit 想要的样子

UPD2。这就是我希望您的 UserPolicy 的样子:

class UserPolicy < ApplicationPolicy
  def profile? #this is the action I have the button in to export data
    return true if user_or_admin?
  end

  private

  def user_or_admin?
    user.id == record.id || user.admin?
  end
end

【讨论】:

  • 你的意思是 def user_or_admin user.id == record.id ||用户管理员?结尾 ?但是我还没有将记录定义为用户,它如何在该特定操作中将记录识别为用户?顺便说一句:我仍然有未知的操作错误
  • @benl96 是的,这就是我的意思。但实际上让我更新我的答案
  • 通过覆盖构造函数我猜你的意思是 attr_reader?我从我的 user_policy 中删除了它。将更新我的问题并添加我的 application_policy。
  • @benl96 我建议您阅读有关 Pundit 的更多信息。问题在于你如何使用 gem。
  • 未知行为与权威人士有何关系?抱歉可能造成误解,但我打开了权威文档,似乎找不到我的错误或我可能在实施过程中搞砸的东西。
【解决方案2】:

我们在 cmets 中对我的原始答案进行了太多讨论。我想澄清一下我的观点。

你写道:

我使用 pundit 作为我的授权 gem,我希望用户 X 只能下载属于用户 X 的用户数据。现在我有 http://localhost:3000/download/x.csv 作为我的链接来接收用户数据。但是如果我登录到另一个用户,例如 user/:id 2,我仍然可以输入 url 并下载 users/3 数据。

所以问题是授权不起作用。我说的对吗?

之后你写道:

更新:按照建议,我尝试在我的 user_controller 并尝试在我看来使用此代码: ...

但这会引发以下错误: ...

因此,您的路由问题超出了原始问题的范围,应该在不同的问题中解决。无论如何,您可以查看this question

所以。如果您的问题是授权 - 只需正确编写策略并在控制器中使用它们。就这些了。

【讨论】:

  • 对不起,是的,你是对的。我没有那样想。但是我还没有拿到授权。如果我不使用下载方法而只使用按钮本身,它就可以正常工作。但是,当我尝试将其放入下载方法以在之后对其进行授权时,会引发错误。控制器和下载操作显然在那里,所以我不明白为什么我不断收到这个错误。就像你说的那样,政策应该写得对,我想我现在就这么做了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多