通过定义虚拟属性获取Rails表单验证中的current_user

时间:2013-01-12 02:22:17

标签: ruby-on-rails ruby validation virtual-attribute

Rails表单验证旨在最容易进入模型。但我需要确保当前用户具有提交帖子所需的权限,current_user变量只能在控制器和视图中访问。

我在similar question中找到了这个答案:

  

您可以为:user_gold定义Book虚拟属性,将其设置在您有权访问current_user的控制器中,然后将其合并到Book验证中。

如何使用我的帖子和用户控制器进行设置,以便模型中可以访问current_user变量?

解决方案:

从应用程序设计的角度来看,这一切都是错误的,因为@ Deefour的回答指出。我改变了它,所以除非条件成立,否则我的视图不会渲染表单。

4 个答案:

答案 0 :(得分:4)

"类似问题"说你可以做这样的事情

class YourModel < ActiveRecord::Base
  attr_accessor :current_user

  # ...
end

然后在您的控制器操作中,您可以执行类似

的操作
@your_model = YourModel.find(params[:id])
@your_model.current_user = current_user
@your_model.assign_attributes(params[:your_model])

if @your_model.valid?
  # ...

然后,您可以在self.current_user的验证方法中使用YourModel


注意我不认为这是你应该做的事情,因为我不会考虑这个&#34;验证&#34;和&#34;授权&#34; 一样多。未经授权的用户甚至无法获得您的操作的一部分,可以保存YourModel实例的此类更新。


至于根据要求对Pundit进行授权,您在app/policies/your_model.rb

中有一个文件
class YourModelPolicy < Struct.new(:user, :your_model)
  def update?
    user.some_privilege == true # change this to suit your needs, checking the "required privileges" you mention
  end
end

在您的ApplicationController

中加入Pundit
class ApplicationController < ActionController::Base
  include Pundit
  # ...
end

然后,在您的控制器操作中,您只需

即可
def update
  @your_model = YourModel.find(params[:id])
  authorize @your_model

  # ...

authorize方法将调用YourModelPolicy的{​​{1}}方法(默认情况下,它会调用与您的操作匹配的方法+ update?如果返回一个假值,将导致403错误。

答案 1 :(得分:2)

不应在模型中进行授权。你认为模特已经承担了很多责任吗?

这是一个控制器的东西,实际上你可以使用像cancan这样的宝石在其他地方使用逻辑,并且在你的控制器中你会做类似的事情:

authorize! :create, Post

答案 2 :(得分:1)

您可以在模型中定义“虚拟属性”,如下所示:

class Book < ActiveRecord::Base
  attr_accessor :current_user
end

它的值可以直接在控制器中设置,如下所示:

class BooksController < ApplicationController
  def create
    book = Book.new
    book.current_user = current_user
    book.save!
  end
end

在模型的验证例程中,您可以像任何其他ActiveRecord字段一样访问它:

def validate_user_permission
  errors[:current_user] = "user does not have permission" unless current_user.is_gold?
end

我不记得ActiveRecord是否属于这种情况,但您可以通过质量分配方法设置虚拟属性,例如createupdatenew在控制器中:

def create
  Book.create!(current_user: current_user)
end

为了做到这一点,您可能需要在模型中添加以下行以启用该虚拟属性的批量分配:

attr_accessible :current_user

答案 3 :(得分:0)

我同意Ismael - 这通常是在控制器中完成的。它不是模型的属性,它是权限问题并且与控制器业务逻辑相关。

如果你不需要像CanCan这样的宝石的所有力量,你可以自己扮演角色。

class BooksController < ApplicationController

  before_filter :gold_required, :only => :create

  def create
    book = Book.new
    book.save!
  end


  # Can be application controller
  private
  def gold_required
    return current_user && current_user.is_gold?
  end

end

您可能也希望将过滤器放在'new'方法上。