Ruby on Rails — эксперт — неизвестное действие для контроллера

этот вопрос относится к этому конкретному вопросу.

Я использую pundit в качестве драгоценного камня авторизации и хочу, чтобы пользователь X мог загрузить только информацию о пользователе, принадлежащую пользователю X. Прямо сейчас у меня есть http://localhost:3000/download.csv в качестве моей ссылки для получения информации о пользователе. Но если я вошел в систему под другим пользователем, например, пользователем/2, я все равно могу ввести URL-адрес и загрузить данные пользователя/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 # это не user_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

person benl96    schedule 28.07.2018    source источник
comment
Вы можете разделить загрузку csv на другое действие/маршрут контроллера (что-то вроде download), а затем авторизовать его отдельно от profile show с помощью метода download? в политике.   -  person Mark Merritt    schedule 29.07.2018
comment
Я создал действие загрузки внутри своего пользовательского контроллера, как я могу указать моему link_to использовать это? ‹p›‹%= link_to(Экспортировать данные в формате CSV, user_path(@user, format: :csv), { :controller =› :user, :action =› :download }, class: btn btn-success) %›‹ /p› не работает   -  person benl96    schedule 29.07.2018
comment
Вы должны создать собственный маршрут, который указывает на ваше действие загрузки. Если вы застряли на этом, я напишу ответ.   -  person Mark Merritt    schedule 29.07.2018
comment
Я создал следующий маршрут get 'download', :to =› 'user#download', но я получаю Действие 'download' не может быть найдено для UserController в результате нажатия кнопки. Также мне нужно удалить аргумент класса, так как я могу разрешить только 3 аргумента, как мне решить и этот? Спасибо, что помогли мне с этим!   -  person benl96    schedule 29.07.2018
comment
Пожалуйста, опубликуйте свои маршруты.rb   -  person Mark Merritt    schedule 29.07.2018
comment
Добавил эту часть.   -  person benl96    schedule 29.07.2018


Ответы (2)


Ваше состояние неправильное @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

УПД. Я перечитал вашу политику. ApplicationPolicy обычно выглядит так:

class ApplicationPolicy
  attr_reader :user, :record

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

Вы переопределили конструктор. Почему? Пусть все останется так, как задумал Пандит.

УПД2. Вот как я ожидаю, что ваша 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
person Nondv    schedule 29.07.2018
comment
Вы имеете в виду def user_or_admin user.id == record.id || пользователь.admin? конец ? Но я еще не определил запись как пользователя, как она распознает запись как пользователя в этом конкретном действии? Кстати: у меня все еще есть ошибка неизвестного действия - person benl96; 29.07.2018
comment
@ benl96 да, я это и имею в виду. Но на самом деле позвольте мне обновить мой ответ - person Nondv; 29.07.2018
comment
Думаю, под переопределением конструктора вы имеете в виду attr_reader? Я удалил его из моего user_policy. Обновлю мой вопрос и также добавлю мою application_policy. - person benl96; 29.07.2018
comment
@ benl96 Я советую вам больше узнать о Pundit. Проблема в том, как вы используете драгоценный камень. - person Nondv; 29.07.2018
comment
Как неизвестное действие связано с пандитом? Извините за возможное недопонимание, но у меня открыта документация эксперта, и я не могу найти свою ошибку или что-то, что я мог испортить при реализации. - person benl96; 29.07.2018
comment
Неизвестная ошибка действия не имеет отношения к вопросу и появилась, когда вы пытались решить исходную проблему. вот что я понял из прочитанного - person Nondv; 29.07.2018
comment
Кажется, я потерял нить. У меня не было проблем с авторизацией, хотя ваше предложение кажется мне логичным. Во всех других вопросах, подобных моему, которые я искал, ничего не проясняет, какая проблема у меня сейчас. Нужно посмотреть это - person benl96; 29.07.2018

Мы слишком много обсуждали в комментариях к моему первоначальному ответу. Я хочу уточнить свою точку зрения.

Вы написали:

Я использую pundit в качестве драгоценного камня авторизации и хочу, чтобы пользователь X мог загружать только пользовательские данные, принадлежащие пользователю X. Прямо сейчас у меня есть http://localhost:3000/download/x.csv в качестве моей ссылки для получения данных пользователя. Но если я вошел в систему под другим пользователем, например, user/:id 2, я все равно могу ввести URL-адрес и загрузить данные users/3.

Так что проблема в том, что авторизация не работает. Я прав?

После этого вы написали:

Обновление: как было предложено, я попытался реализовать новое действие загрузки в моем user_controller и попытался использовать этот код в своем представлении: ...

но это выдает следующую ошибку: ...

Таким образом, проблема с вашей маршрутизацией выходит за рамки исходного вопроса и должна решаться в другом. В любом случае, вы можете проверить этот вопрос.

Так. Если ваша проблема в авторизации - просто напишите правильно свои политики и используйте их в своем контроллере. Это было бы все.

person Nondv    schedule 29.07.2018
comment
Извините, да, вы правы. Я не думал об этом таким образом. Но до авторизации я еще не дошел. Если я не использую метод загрузки, а просто использую саму кнопку, все работает нормально. Однако, когда я пытаюсь поместить это в метод загрузки, чтобы впоследствии авторизовать его, возникает ошибка. Контроллер и действие загрузки явно присутствуют, поэтому я не понимаю, почему я продолжаю получать эту ошибку. Как вы сказали, политики должны быть написаны правильно, и я думаю, что сделал это сейчас. - person benl96; 29.07.2018