问题
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