7

JSON 応答を返す Rails API コントローラーが既にあります。フロントエンド Javascript (およびモバイル アプリ) で値をレンダリングするために使用されます。

ここで、ReactJS を使用してこれらの値を事前にレンダリングしたいと思います。

#app/controllers/api/v1/products_controller.rb
module API
    module V1
        class ProductsController < ApplicationController
            def index
                @products = Product.all #this could  be acomplex multi-line statements. 
                #rendered in api/v1/products/index.json.jbuilder
            end
        end
    end
end

#app/controllers/products_controller.rb
class ProductsController < ApplicationController
    def index
        #How to do this efficiently?
        @products_json = #Call to internal /api/v1/products/index for prerender purpose.
        @user_json = #Call to internal /api/v1/user/show for prerender purpose.
    end
end

#app/views/products/index.html.erb
<%= react_component('ProductsList', @products_json, {prerender: true}) %>
<%= react_component('UserProfile', @user_json, {prerender: true}) %>

/api/v1/products内部およびURL を効率的に呼び出すにはどうすればよいですか/api/v1/user(たとえば、自分のサーバーに HTTP GET 要求を行わずに)。

4

2 に答える 2

3

ビューに API コードを再利用したいというあなたの希望に同意します。これにより、アプリケーションの保守性が大幅に向上します。

範囲を少し変えてみたらどうですか?コントローラー メソッドを呼び出す代わりに、ロジックを新しい Ruby クラスに移動します。

このクラスの仕事は、オブジェクトを JSON 文字列に変換することなので、「シリアライザー」と呼ばれます。私のアプリでは、app/serializers/{model_name}/さまざまなシリアライザー クラスを格納する必要があります。

シリアライザーの例を次に示します。

# app/serializers/product/api_serializer.rb
class Product::APISerializer 
  attr_reader :product, :current_user 

  def initialize(product, current_user)
    @product = product 
    @current_user = current_user
  end 

  # Return a hash representation for your object
  def as_json(options={}) # Rails uses this API
    {
      name: product.name,
      description: product.description,
      price: localized_price,
      categories: product.categories.map { |c| serialize_category(c) },
      # ... all your JSON values
    }
  end 

  private 

  # For example, you can put logic in private methods of this class.
  def localized_price 
    current_currency = current_user.currency
    product.price.convert_to(current_currency)
  end 

  def serialize_category(category)
    { name: category.name }
  end
end

次に、このシリアライザーを使用して API 応答を作成します。

class API::V1::ProductsController < ApplicationController 
  def index 
    products = Product.all 
    products_json = products.map do |product|
      serializer = Product::APISerializer.new(product, current_user)
      serializer.as_json
    end 
    render json: products_json
  end
end

その後、 UI コントローラーでシリアライザーを再度使用できます。

class ProductsController < ApplicationController 
  def index 
    products = Product.all 
    @products_json = products.map do |product|
      serializer = Product::APISerializer.new(product, current_user)
      serializer.as_json
    end 
    # render view ... 
  end
end

どちらの場合も同じシリアライザーを使用したため、製品の JSON 表現は同じになります。

このアプローチにはいくつかの利点があります。

  • シリアライザはプレーンな Ruby クラスなので、簡単に記述およびテストできます
  • コントローラー間で JSON ロジックを簡単に共有できます
  • 非常に拡張可能です。別の目的で JSON が必要な場合は、新しいシリアライザーを追加して使用するだけです。

これにActiveModel Serializersを使用する人もいますが、私は使用しません。as_json私は 1 年前に AMS を試しましたが、アプリ内のすべてのオブジェクトをオーバーライドするため、気に入らなかったため、私の場合は重大な変更が発生しました!

于 2015-10-07T03:39:20.127 に答える
1

これを試して:

def index
  @products = Product.all
  @products_json render_to_string('/api/v1/products/index', formats: [:json])
  # etc...
end
于 2015-09-29T12:01:19.143 に答える