在Rails 3中使用Devise和attr_accessible进行响应

| 我正在用Rails 3构建API,并使用devise处理一些身份验证。 我通常使用response_with方法为各种资源返回xml / json。 例如GET /groups.xml将路由到
def index
  respond_with Group.all
end
对于各种资源,这在我的网站上都能正常工作,并返回格式正确的json或xml,其中包含每个组的所有属性。 但是,当我调用GET /users.xml时,它只响应每个用户属性的有限子集。事实证明,这里只会返回attr_assessible中定义的属性-我怀疑这是设计的“功能”,因为其他任何模型都不是这样。 谁能启发我? 编辑:这是在Devise 1.4.2中修复的。详情请见下文     
已邀请:
        您的怀疑是正确的。 Devise Authenticatable模块将覆盖#to_xml和#to_json,以首先检查该类是否响应#accessible_attributes方法,如果响应,则仅将输出限制为#accessible_attributes返回的那些属性。来自authenticatable.rb的代码在这里:
  %w(to_xml to_json).each do |method|
    class_eval <<-RUBY, __FILE__, __LINE__
      def #{method}(options={})
        if self.class.respond_to?(:accessible_attributes)
          options = { :only => self.class.accessible_attributes.to_a }.merge(options || {})
          super(options)
        else
          super
        end
      end
    RUBY
  end
您会注意到,此代码将#accessible_attributes的结果合并到任何传入的选项中。因此,您可以指定:only选项,例如:
.to_xml(:only => [:field, :field, :field])
这将覆盖对Devise施加的限制,并生成仅包含您指定的字段的xml输出。您将需要包括要公开的每个字段,因为一旦使用:only,您将胜过常规操作。 在这种情况下,我认为您将无法继续在控制器中使用response_with快捷方式,因为您将需要直接指定xml输出。您可能必须退回到老式的response_to块:
respond_to do |format|
  format.xml { render :xml => @users.to_xml(:only => [:field, :field, :field]) }
  format.html
end
正如您已经发现的那样,您还可以仅在模型类中添加要通过attr_accessible公开的其他字段。但是,这将带来使这些字段可大规模分配的附加副作用,在这种情况下,您可能不一定希望这样做。     
        Devise的较旧版本(<1.4.2)对to_json和to_xml方法执行了monkeypatch,使用attr_accessible中定义的属性覆盖:only => []选项。烦死了 现在已更改,因此覆盖了serializable_hash,并且持久化了to_json或to_xml中设置的:only => [:attribute]选项。 以我为例,我自己亲自完成了对to_json的monkeypatching,并为所有ActiveRecord模型添加了api_accessible方法。
class ActiveRecord::Base

  def to_json(options = {}, &block)
    if self.class.respond_to?(:api_attributes)
      super(build_serialize_options(options), &block)
    else
      super(options, &block)
    end
  end

  class << self
    attr_reader :api_attributes
    def api_accessible(*args)
      @api_attributes ||= []
      @api_attributes += args
    end
  end

  private

    def build_serialize_options(options)
      return options if self.class.api_attributes.blank?
      methods = self.class.instance_methods - self.class.attribute_names.map(&:to_sym)
      api_methods = self.class.api_attributes.select { |m| methods.include?(m) }
      api_attrs = self.class.api_attributes - api_methods
      options.merge!(only: api_attrs) if api_attrs.present?
      options.merge!(methods: api_methods) if api_methods.present?
      return options
    end

end
这意味着您现在可以定义在调用to_json时默认公开的属性(和方法!)列表。 Respond_with也使用to_json,因此它适用于API。 例如,user.rb
class User < ActiveRecord::Base

 devise :database_authenticatable, :registerable, :confirmable,
         :recoverable, :rememberable, :trackable, :validatable

  #Setup accessible (or protected) attributes for your model
  attr_accessible :email,
                  :password,
                  :password_confirmation,
                  :remember_me,
                  :first_name,
                  :last_name,


  api_accessible :id,
                 :name,
                 :created_at,
                 :first_name,
                 :last_name,
                 :some_model_method_also_works
end
    

要回复问题请先登录注册