Ruby on rails 3 检查控制器实例变量是否属于当前用户的before\u筛选器

Ruby on rails 3 检查控制器实例变量是否属于当前用户的before\u筛选器,ruby-on-rails-3,authentication,activerecord,devise,before-filter,Ruby On Rails 3,Authentication,Activerecord,Devise,Before Filter,目前,我有一个为餐馆设置的CRUD资源。一个老板有很多餐馆,一个餐馆属于他的老板。任何用户都可以访问餐厅的“索引”和“显示”视图。但是,为了创建一家新餐厅,店主必须登录。我实现了这个设计,效果很好。我的问题是,在能够编辑、更新或销毁餐厅之前,确保餐厅的当前所有者拥有该餐厅 我在创建before_筛选器时遇到问题,该筛选器将检查登录所有者(当前所有者)是否是登录所有者试图查看的餐厅的所有者 在设置Before_过滤器之前,我快速创建了一个#check_if_owner方法,并将其放置在编辑操作中。

目前,我有一个为餐馆设置的CRUD资源。一个老板有很多餐馆,一个餐馆属于他的老板。任何用户都可以访问餐厅的“索引”和“显示”视图。但是,为了创建一家新餐厅,店主必须登录。我实现了这个设计,效果很好。我的问题是,在能够编辑、更新或销毁餐厅之前,确保餐厅的当前所有者拥有该餐厅

我在创建before_筛选器时遇到问题,该筛选器将检查登录所有者(当前所有者)是否是登录所有者试图查看的餐厅的所有者

在设置Before_过滤器之前,我快速创建了一个#check_if_owner方法,并将其放置在编辑操作中。如果店主不拥有餐厅,则应将其重定向到上一页。但是,由于某些原因,我收到以下错误:

ActiveRecord::RecordNotFound in RestaurantsController#edit

Couldn't find Restaurant with id=4 [WHERE "restaurants"."owner_id" = 1]
我不确定为什么会发生这种情况,因为当我在控制台中运行#check_ownership方法时,它返回false,这正是我希望在当前#u所有者不拥有餐厅的情况下该方法执行的操作。如果在控制台中返回false,用户不应该被重定向到上一页,而不是接收RecordNotFound错误吗?我不知道为什么会这样

发布的是代码的其余部分

class RestaurantsController < ApplicationController
  before_filter :authenticate_owner!, except: [:index, :show]
  # before_filter :check_if_owner, only: [:edit, :update, :destroy]
  def index
    @restaurants = Restaurant.all
  end

  def show
    @restaurant = Restaurant.find(params[:id])
  end

  def new
    @restaurant = current_owner.restaurants.new
  end

  def create
    @restaurant = current_owner.restaurants.build(params[:restaurant])
    if @restaurant.save
      redirect_to restaurants_path
    else
      flash[:error] = "<ul>" + @restaurant.errors.full_messages.map{|o| "<li>" + o + "</li>" }.join("") + "</ul>"
      redirect_to new_restaurant_path
    end
  end

  def edit
    check_if_owner(Restaurant.find(params[:id]))
    @restaurant = current_owner.restaurants.find(params[:id])
  end

  def update
    @restaurant = current_owner.restaurants.find(params[:id])
    @restaurant.update_attributes(params[:restaurant])
    redirect_to restaurant_path(@restaurant)
  end

  def destroy
    @restaurant = current_owner.restaurants.find(params[:id])
    @restaurant.destroy
    redirect_to restaurants_path
  end

  private

    def check_if_owner(restaurant)
      debugger
      if current_owner.check_ownership(restaurant)
        return
      else
        redirect_to :back
      end
    end

end


class Owner < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :token_authenticatable, :confirmable,
  # :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

  # Setup accessible (or protected) attributes for your model
  attr_accessible :email, :password, :password_confirmation, :remember_me, :name
  # attr_accessible :title, :body

  has_many :restaurants

  validates :name, presence: true
  validates :email, presence: true

  def check_ownership(restaurant)
    !self.restaurants.find_by_id(restaurant.id).nil?
  end

end
class RestaurantController”+@restaurant.errors.full_messages.map{o}“
  • ”+o+“
  • ”}。加入(“”+”“) 重定向到新餐厅路径 结束 结束 定义编辑 检查所有者(Restaurant.find(params[:id])) @restaurant=当前所有者.restaurants.find(参数[:id]) 结束 def更新 @restaurant=当前所有者.restaurants.find(参数[:id]) @餐厅。更新_属性(参数[:餐厅]) 重定向到餐厅路径(@restaurant) 结束 def销毁 @restaurant=当前所有者.restaurants.find(参数[:id]) @餐厅,毁灭 重定向到餐厅路径 结束 私有的 def检查业主(餐厅) 调试器 如果为当前所有者,请检查所有者(餐厅) 返回 其他的 重定向到:返回 结束 结束 结束 类所有者
    用以下方法解决了这个问题:

    class RestaurantsController < ApplicationController
      before_filter :authenticate_owner!, except: [:index, :show]
      before_filter :check_if_owner, only: [:edit, :update, :destroy]
    
      private
    
      def check_if_owner
        if current_owner.has_ownership?(Restaurant.find(params[:id]))
          return
        else
          flash[:error]= "You do not have permission to do that." 
          redirect_to :back
        end
      end
    end
    

    首先,我将把责任放在检查餐厅的所有权上,而不是所有者,特别是因为您正在RestaurantController中实施此检查

    而且,你似乎在设计所有权检查。真的,你只需要检查一下餐厅的
    restaurant.owner==current\u owner

    餐厅.rb

    def owned_by?(current_owner)
      owner == current_owner
    end
    
    def manages?(object)
      object.respond_to?(:owner) && object.owner == self
    end
    
    如果您认为将在其他地方重用此方法,则只需要在模型中使用此方法(而不是在过滤器之前在控制器中作为单行)

    或者,如果您的所有者要管理许多不同种类的对象,您可以将权限检查保留在所有者模型中,使其更加灵活

    owner.rb

    def owned_by?(current_owner)
      owner == current_owner
    end
    
    def manages?(object)
      object.respond_to?(:owner) && object.owner == self
    end
    
    在ActiveRecord查询中,使用find和find_by_id时使用的方法是脆弱的,不是首选方法。具体地说,当没有结果时,find_by_*会抛出一个异常。另一方面,使用where(:id=>id)将返回空数组,如果没有结果,则返回nil

    查看这些内容,以获得更多见解和最佳实践。

    谢谢卡洛斯!这非常有用。