共识是你不应该嵌套超过1级的资源。所以,如果我有3个这样的模特 (以下只是假设情况)
用户has_many Houses has_many Tenants
并遵守以上所述
map.resources :users, :has_many => :houses
map.resorces :houses, :has_many => :tenants
现在我希望用户能够编辑他们的房屋和他们的租户详细信息,但我想阻止他们通过伪造网址的user_id部分来尝试编辑其他用户房屋和租户。所以我创建了一个像这样的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)
但是在tenents案例中
tenant house_tenent_path(@house)
没有传递用户ID。但我可以通过@ house.user.id来获取用户ID,但是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
它完成了这项工作,但我想知道是否有更优雅的方式。每次我添加一个需要防止用户伪造的新资源时,我必须不断添加条件。我不认为会有很多案例,但如果有的话,我想知道更好的方法。
答案 0 :(得分:1)
执行以下操作:
class User < ActiveRecord::Base
has_many :houses
has_many :tenants
end
class House < ActiveRecord::Base
belongs_to :user
has_many :tenants
end
class Tenant < ActiveRecord::Base
belongs_to :user
belongs_to :house
end
在您的过滤器中执行以下操作:
def kill_session(message)
@current_user_session.destroy
flash[:error] = message
redirect_to login_url()
end
def prevent_user_acting_as_other_user
if params[:user_id] and params[:user_id] != @current_user.id
kill_session("You don't have access to this page")
elsif params[:house_id] and !@current_user.houses.exists?(params[:house_id])
kill_session("You don't have access to this page")
elsif params[:tenant_id] and !@current_user.tenants.exists?(params[:tanant_id])
kill_session("You don't have access to this page")
end
end