新手问题 Grape 方法小汇!

xiaohesong · 2016年02月16日 · 最后由 xiaohesong 回复于 2016年02月17日 · 5547 次阅读
用 grape 写了两天的 api,写个方法小结,以备后用。废话不多说,直接上代码。

entity 内的用法

`app/apis/v1/customers.rb`
module V1
  class Customers < Grape::API
    resource :customers, desc: "客户相关" do
      add_desc "客户列表"
      get do
        present current_store.store_customers, with: ::Entities::Customer, type: :default
      end

      add_desc "客户详情"
      get ":id", requirements: { id: /[0-9]*/ } do
        present StoreCustomer.find(params[:id]), with: ::Entities::Customer, type: :full
      end
    end
  end
end

那么我们再来看看对应的显示层。 app/apis/entities/customer.rb

module Entities
  class Customer < Grape::Entity
    expose :age, if: {type: :default}  #客户列表显示(对应的type)
    expose :phone_number, if: {type: :full}   #客户详情显示(对应的type)
    expose :name   #客户列表,客户详情都会显示
    expose(:login_name, if: {type: :default}) {|model|model.phone_number}  #自定义expose显示的名称,判断加在()里。
  end
end

NOTE: expose(:xx) 等同于官网给出的块的形式。

Grape 内的路由问题

对于一些嵌套路由,可以使用 grape 的嵌套路由。
route_param :customer_id do
  resource :girls do
  end
end
# 对应的路由为 xx/customers/{customer_id}/girls

Grape 内只可以调用类方法?

module V1
  class Customer < Grape::API
    get do
      customer_params
      present current_store.store_customers, with: ::Entities::Customer
    end
    def customer_params
      "hello"
    end
  end
end
# 有报错为undefined local variable or method `customer_params'

如若将 方法转换成类方法呢?

你去试试吧😰

做如下改变再试试:
module V1
  class Customer < Grape::API
    get do
      customer_params
      present current_store.store_customers, with: ::Entities::Customer
    end
    helpers do
      def customer_params
        "hello"
      end
    end
  end
end

发现加上 helpers 还是有点爱的。

创建功能出现的问题

grape 本身拥有一个 params 处理机制。
declared(params, include_missing: false)

用这个写呀写呀的。。

declared(params, include_missing: false).slice(:name, :age)
#这样取出需要的参数

最后测试发现,报错 ActiveModel::ForbiddenAttributesError。 因为 strong_params 的安全机制。 不过也不是不可以,他提供了一个 gem 去解决这个情况:

Additionally, if the version of your Rails is 4.0+ and the application uses the default model layer of ActiveRecord, you will want to use the hashie-forbidden_attributes gem. This gem disables the security feature of strong_params at the model layer, allowing you the use of Grape's own params validation instead.

代码如下: https://github.com/rails/strong_parameters/blob/master/lib/active_model/forbidden_attributes_protection.rb

我是个保守的人,还是用 strong params 来搞吧。
def customer_params
  customer = ActionController::Parameters.new(params)
  customer.permit(:name, :age)
end

grape-doc: http://www.rubydoc.info/github/intridea/grape-entity/Grape 不是之处,欢迎各位不吝指出。☺

entity 内的用法

  • 用子类代替 if
  • 别名可以用 as
module Entities
  class CustomerSummary < Grape::Entity
    expose :age, :name
    expose :phone_number, as: :login_name
  end

  class Customer < CustomerSummary
    expose :phone_number, :login_name
  end
end

创建功能出现的问题

用 Grape 的话,就用它提供的 params validation 吧,没必要再用 strong params

#1 楼 @42thcoder 用子类,感觉还是需要去判断下吧。毕竟对外显示的类就是 Customer,所以不管显示还是列表,都是得经过 Customer 的 Entity。 你说的别名用 as 的确是不错,不过多表关联的场景还是用 () 较好吧,如下:

class Customer < ActiveRecord::Base
  has_one :girl 
end
class Girl < ActiveRecord::Base
  belongs_to :customer
end
class Customer < Grape::Entity
  expose(:name){|model|model.girl.name}
end

Grape 的 params validation 不是很了解,用这个做创建的功能,不会出现 ActiveModel::ForbiddenAttributesError 的报错吗,回去有时间去看看 😄

#2 楼 @xiaohesong

对外显示的也变了啊:

present StoreCustomer.find(params[:id]), with: ::Entities::CustomerSummary

present StoreCustomer.find(params[:id]), with: ::Entities::Customer

多表关联的场景用 delegate 更好吧

class Customer < ActiveRecord::Base
  has_one :girl 
  delegate :name, to: :girl
end

class Customer < Grape::Entity
  expose :name
end

又或者这样:

class Customer < Grape::Entity
  expose :name

  private
  def name
    object.girl.name
  end
end

params validation 应该是 Grape 最好用的特性之一,配合 Swagger 很方便

#3 楼 @42thcoder 对外显示变了,那就改变了初衷了,放在一个 entity 文件下的初衷。 delegate 这个的确是不错,蛮好的,不过再多一层的关联,处理起来就显得 () 方便一些了(对于grapedelegate没有使用过,或许可以更简便)。 至于这种方式:

class Customer < Grape::Entity
  expose :name

  private
  def name
    object.girl.name
  end
end

在多层关联太深的情况下考虑使用,可以接受的长度内还是用块比较舒服点 😭 你说的grapeparams validation,应该就是我上面说的declared吧,他不是需要去借助gem 'hashie-forbidden_attributes'这个gem的吗?你创建一个数据的时候,不加这个 gem 可以吗?这个倒是一直没有找到好的方法去解决。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号