Use Pundit with strong parameters in Rails API

无人久伴 提交于 2020-01-16 12:03:18

问题


How is it possible to use Pundit strong parameters when working with JSON API if a model contains some relations? I have already posted a question that explained how to work around with it in case of a single model. Son here is what works:

# posts_controller.rb

def update
    if @post.update(permitted_attributes(@post))
      render jsonapi: @post
    else
      render jsonapi: @post.errors, status: :unprocessable_entity
    end
  end

private

  def set_post
    @post = Post.find(params[:id])
  end

  def post_params
    ActiveModelSerializers::Deserialization.jsonapi_parse(
      params,
      only: [:title, :body, :user]
    )
  end

  def pundit_params_for(_record)
    params.fetch(:data, {}).fetch(:attributes, {})
  end

Unfortunately it will fail to extact models defined in relationships block of the request JSON, foe example:

"relationships"=>{"country"=>{"data"=>{"type"=>"countries", "id"=>"1"}}, "language"=>{"data"=>{"type"=>"languages", "id"=>"245"}}}

Any ideas ?


回答1:


I figured out how to make it work. The method pundit_params_for defined in the PostsController should return ActionController::Parameters object adn should reuse already extracted data in post_params using ActiveModelSerializers::Deserialization.jsonapi_parse! method:

# posts_controller.rb

private

  def set_post
    @post = Post.find(params[:id])
  end

  def post_params
    ActiveModelSerializers::Deserialization.jsonapi_parse!(
      params,
      only: [:body, :framework, :title, :user]
    )
  end

  def pundit_params_for(_record)
    ActionController::Parameters.new(post_params)   
  end

So I had to pass in post_params to ActionController::Parameters constructor. Then in the controller update action, you will have to use permitted_attributes method as explained in Pundit docs as follows:

# posts_controller.rb

def update
  if @post.update(permitted_attributes(@post))
    render jsonapi: @post
  else
    render jsonapi: @post.errors, status: :unprocessable_entity
  end
end

As for create action, it has nothing special and just follows the docs of Pundit:

def create
  @post = Post.new(post_params)
  authorize @post
  if @post.save
    render jsonapi: @post, status: :created, location: @post
  else
    render jsonapi: @post.errors, status: :unprocessable_entity
  end
end

And here how PostPolicy looks like:

# policies/post_policy.rb

class PostPolicy < ApplicationPolicy
  def permitted_attributes
    if user.admin?
      [:title, :body, :framework_id, :user_id]
    else
      [:body]
    end
  end

  def create?
    user.admin?
  end
end

Hope this helps.



来源:https://stackoverflow.com/questions/59180773/use-pundit-with-strong-parameters-in-rails-api

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!