Консенсус в том, что вы не должны вкладывать ресурсы глубже, чем на 1 уровень. Так что, если у меня есть 3 модели, как это
(ниже только гипотетическая ситуация)
Пользователь has_many Houses has_many Арендаторы
и соблюдать вышеизложенное, я делаю
map.resources :users, :has_many => :houses
map.resorces :houses, :has_many => :tenants
Теперь я хочу, чтобы пользователь мог редактировать как свои дома, так и информацию об арендаторах, но я хочу, чтобы они не пытались редактировать дома и арендаторы других пользователей, подделывая часть user_id URL. Поэтому я создаю before_filter, как этот
def prevent_user_acting_as_other_user
if User.find_by_id(params[:user_id]) != current_user()
@current_user_session.destroy
flash[:error] = "Stop screwing around wiseguy"
redirect_to login_url()
return
end
end
для домов это просто, потому что user_id передается через
edit_user_house_path(@user, @house)
но в случае арендаторов
tenant house_tenent_path(@house)
идентификатор пользователя не передается. Но я могу получить идентификатор пользователя, выполнив @ house.user.id, но затем идентификатор должен изменить приведенный выше код на этот.
def prevent_user_acting_as_other_user
if params[:user_id]
@user = User.find(params[:user_id]
elsif params[:house_id]
@user = House.find(params[:house_id]).user
end
if @user != current_user()
#kick em out
end
end
Это делает работу, но мне интересно, есть ли более элегантный способ. Каждый раз, когда я добавляю новый ресурс, который нуждается в защите от подделки пользователя, мне придется постоянно добавлять условные выражения. Я не думаю, что будет много случаев, но хотел бы знать лучший подход, если таковой существует.