2011-06-25 25 views
2

我正在用Rails 3構建一個API,使用devise來處理一些身份驗證。在Rails 3中使用Devise&attr_accessible響應3

我通常使用respond_with方法爲各種資源返回xml/json。

如GET /groups.xml意志路線

def index 
    respond_with Group.all 
end 

這在我的網站能正常工作的各種資源,並返回一個包含每個組的所有屬性很好的格式化的JSON或XML。

但是,當我調用GET /users.xml時,它只會響應每個用戶屬性的有限子集。事實證明,只有在attr_assessible中定義的屬性纔會在這裏返回 - 我懷疑這是設計的「特徵」,因爲對於任何其他模型都不是這樣。

任何人都可以啓發我嗎?

編輯:這是固定在Devise 1.4.2。詳情請見下方

回答

1

Devise的舊版本(< 1.4.2)在to_json和to_xml方法上執行monkeypatch,並使用attr_accessible中定義的屬性覆蓋:only => []選項。煩人。

現在已經改變了,所以serializable_hash會被覆蓋,而to_json或to_xml中設置的任何:only => [:attribute]選項都會被保留。

在我的情況下,我最終完成了自己的to_json腳本,併爲所有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 
1

您的懷疑是正確。該設計可認證模塊覆蓋#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到任何傳入的選擇的結果。因此,你可以指定一個:只有選項,如:

.to_xml(:only => [:field, :field, :field]) 

這將覆蓋設計強加的限制,併產生XML輸出僅包含您指定的字段。你需要包括你想暴露的每一個領域,因爲一旦你使用:只有你會勝過正常的操作。

在這種情況下,我認爲您不能繼續在控制器中使用respond_with快捷方式,因爲您需要直接指定xml輸出。你可能不得不回落到一個老派的的respond_to塊:

respond_to do |format| 
    format.xml { render :xml => @users.to_xml(:only => [:field, :field, :field]) } 
    format.html 
end 

正如你已經發現了,你也可以通過只attr_accessible模型類添加要曝光的附加字段。但是,這會使這些字段具有大量可分配的副作用,並且在這種情況下您可能不一定要這樣做。

+1

感謝。真的很煩人,他們沒有提供一種關閉這種行爲的方式。 這是非常荒謬的假設attr_accessible是說「我想公開這些,只有這些屬性在我的API」 – tomblomfield