2013-02-14 4 views
2

в моих контроллеров я использую что-то вроде этого много, чтобы убедиться, что project действительно принадлежит данный user:Каков наилучший способ обработки ошибок ID в Ruby on Rails?

private 

def authorized_user 
    @project = Project.find(params[:id]) 
    redirect_to root_path unless current_user?(@project.user) 
end 

Это прекрасно работает, потому что пользователь А не может видеть проекты пользователя B (он перенаправляется на корневая страница).

Однако это работает только до тех пор, пока запрашиваются URL-адреса project, которые действительно существуют.

Например, URL http://localhost:3000/projects/1 либо отобразит проект пользователя, либо перенаправляет его на корневой URL (если другой пользователь пытается получить доступ к проекту).

Но когда я пытаюсь получить доступ к проекту, который не существует вообще в базе данных, например. как это:

http://localhost:3000/projects/777

... Я получаю некрасивый ActiveRecord::RecordNotFound ошибку:

Couldn't find Person with id=777

Что бы лучший способ улучшить пользовательский опыт здесь?

У меня никогда не было развернуто Проект Rails еще нет, поэтому я даже не знаю, как эта ошибка будет выглядеть в режиме производства.

Может ли кто-нибудь помочь?

Благодаря ...

ответ

5

Я лично хотел бы использовать это:

@project = Project.where(id: params[:id]).first 

Если проект не существует, @project будет ноль.

+0

ОК, спасибо! Что именно делает «первый» в этом случае? Я думал, что «первый» выбирает первую запись ... Но я n00b ... – Tintin81

+0

Ну, чтобы исправить вашу нуобильность, прочтите это руководство: [Интерфейс запросов] (http://guides.rubyonrails.org/active_record_querying. HTML). Вы найдете ответ. :) –

+0

Хорошо, я понимаю. Он возвращает 'nil', а не исключает исключение. Но я должен проверить значения nil в следующей строке, тогда ... – Tintin81

2

В зависимости от того, как вы хотите, чтобы справиться с этим, вы можете использовать

@project = Project.find_by_id(params[:id]) 

Это позволит @project быть нулевым, если не найдено ни одной записи, и вы вручную должны обрабатывать случай.

Другим решением является бросок 404, который имеет смысл, поскольку ресурса там нет. Вы можете легко сделать это в любом контроллере (или контроллера приложений) с помощью:

rescue_from ActiveRecord::RecordNotFound, :with => :not_found 

def not_found 
    raise ActionController::RoutingError.new('Not Found') 
end 

Это приведет к чему-то вроде:

class ApplicationController < .. 
    rescue_from ActiveRecord::RecordNotFound, :with => :not_found 

    def not_found 
    raise ActionController::RoutingError.new('Not Found') 
    end 
end 

Последнее решение будет показывать пользователю по умолчанию 404 (НЕ FOUND). В первом случае у вас больше контроля, но за счет этого везде

Надеюсь, что это поможет.

+0

Я думаю, что ваше второе решение намного лучше, потому что оно не включает в себя модификацию кода, созданного эшафотом, и может быть реализовано чисто с помощью нескольких строк в контроллере приложения. – bdares

+0

Вы имеете в виду решение Серхио лучше? Хорошо, но как бы добавить это в контроллер приложения? – Tintin81

+0

Отредактировал свой ответ, чтобы сделать его немного понятнее. – Novae

1

Прежде всего, чтобы избежать не авторизованным пользователям доступ к проектам, вы должны охват ваши методы находят:

current_user.projects.find(params[:id]) 

Таким образом, вы получите «Не удалось найти проект с идентификатором» ошибка в развитии. Чтобы избежать этого, вы можете использовать:

current_user.projects.find_by_id(params[:id]) 

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

Наконец, чтобы бросить 403 Запрещено, а не 404 Не найдено, вы можете подумать об использовании одного из многих драгоценных камней авторизации (cancan by Ryan Bates).

Редактировать: О, и в процессе производства, ActiveRecord :: RecordNotFound будет отображать страницу 404.html, a.k.a., это не те проекты, которые вы ищете.

+0

Очень хороший момент, который вы сделали здесь. Большое спасибо за вашу помощь! Wow, получил немало действительно хороших ответов, чтобы выбрать из этой темы ... – Tintin81

+0

Чтобы было ясно, что перенаправление ответа на 404.html - это отличные примеры того, как изменить поведение по умолчанию, но они не нужны в этом дело. Как я уже сказал, в производстве Rails делает это по умолчанию. И в разработке вы хотите получить страницу с исключениями, а не страницу 404. – Pandaamonium

1

Try:

class ApplicationController < ActionController::Base 
    rescue_from ActiveRecord::RecordNotFound, :with => :render_404 
    # Render 404 page when record not found 
    def render_404  
     render :file => "#{RAILS_ROOT}/public/404.html", :status => 404 
    end 
end 
+0

Спасибо за помощь! – Tintin81

Смежные вопросы