Как я могу иметь дело с недействительными идентификаторами в before_filter? - PullRequest
3 голосов
/ 06 июня 2011

Допустим, мой контроллер выглядит так:

class MyController < ApplicationController
  before_filter :find_user,:only => [:index,:create,:update,:destroy]
  def index
     @some_objects = @user.objects.all
  end

  ...

  private
  def find_user
    @user = User.find(params[:user_id])
  end

end

Если параметр user_id не существует, @user будет равен нулю. Я думаю, что это не так:

def index
   if @user
      @some_objects = @user.objects.all
   else
      # ?
   end
end

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

Ответы [ 4 ]

2 голосов
/ 06 июня 2011

Если параметр user_id не существует, метод find выдает исключение ActiveRecord::RecordNotFound.Это исключение попадает в before_filter и выдает ошибку.Все последующие фильтры и действие index вызываться не будут.

class MyController < ApplicationController
  before_filter :find_user,:only => [:index,:create,:update,:destroy]
  def index
     @some_objects = @user.objects.all
  end

  private
  def find_user
    @user = User.find(params[:user_id])
  rescue ActiveRecord::RecordNotFound
    # render or redirect_to error
  end

end
1 голос
/ 06 июня 2011

Лучший способ сделать его абсолютно сухим - использовать выделенный драгоценный камень: inherited_resources

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

Конечно, вы можете добавить нужные вам конкретные области, см. Учебник.

1 голос
/ 06 июня 2011

Я думаю, что он должен быть помещен в тот же фильтр:

private
def find_user
  @user = User.find_by_id(params[:user_id])
  redirect_to where_you_want_to_go_when_no_user_url unless @user #for example login page
end

Если вы хотите визуализировать действия вашего контроллера даже без @user и вам всегда нужны @some_objects (и вы не хотите, чтобы переменная была нулевой), у вас может быть другой before_filter:

def get_some_objects
  @some_objects = @user.present? ? @user.objects.all : []
end

или объединение обоих параметров (перенаправить или установить переменную some_objects):

def set_variables
  @user = User.find_by_id(params[:user_id])
  if @user
    @some_objects = @user.objects.all
  else
    redirect_to where_you_want_to_go_when_no_user_url
  end
end

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

РЕДАКТИРОВАТЬ: изменить 'find' на 'find_by_id', чтобы избежать ошибок, когда id равен нулю или пользователь для данного идентификатора не существует.

0 голосов
/ 06 июня 2011

Когда вы запрашиваете определенный идентификатор, а AR не может его найти, выдается ошибка RecordNotFound. Вы должны поймать это с чем-то вроде:

irb(main):025:0> begin
irb(main):026:1* Location.find 100
irb(main):027:1> rescue ActiveRecord::RecordNotFound => e
irb(main):028:1> puts "Oops: #{e.message}"
irb(main):029:1> end
Oops: Couldn't find Location with ID=100
=> nil

Если вы хотите применить что-либо ко всем контроллерам, вам, вероятно, следует подумать о добавлении вашего метода в ApplicationController ...

...