2

Rails 3でAPIを構築しており、deviseを使用して認証の一部を処理しています。

私は通常、respond_withメソッドを使用して、さまざまなリソースのxml/jsonを返します。

たとえば、GET/groups.xmlはにルーティングされます

def index
  respond_with Group.all
end

これは、さまざまなリソースのサイト全体で正常に機能し、各グループのすべての属性を含む適切にフォーマットされたjsonまたはxmlを返します。

ただし、GET /users.xmlを呼び出すと、各ユーザーの属性の限られたサブセットでのみ応答します。attr_assessibleで定義された属性のみがここに返されることがわかります。他のモデルには当てはまらないため、これはdeviseの「機能」であると思われます。

誰かが私を啓発できますか?

編集:これは、Devise1.4.2で修正されています。詳細は以下をご覧ください

4

2 に答える 2

1

古いバージョン(<1.4.2)のDeviseは、to_jsonメソッドとto_xmlメソッドでモンキーパッチを実行し、:only=>[]オプションをattr_accessibleで定義された属性で上書きしました。迷惑。

これが変更され、代わりに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
于 2011-07-08T18:22:41.187 に答える
1

あなたの疑いは正しいです。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 を使用すると、通常の操作よりも優先されるため、公開するすべてのフィールドを含める必要があります。

この場合、xml出力を直接指定する必要があるため、コントローラーでrespond_withショートカットを引き続き使用できるとは思いません。おそらく、古い学校のRespond_toブロックにフォールバックする必要があります。

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

既に発見したように、モデル クラスのattr_accessibleを介して公開するフィールドを追加することもできます。ただし、これには、これらのフィールドを一括割り当て可能にするという追加の副作用があり、この状況では必ずしもそれが必要ではない場合があります。

于 2011-06-25T01:17:32.860 に答える