Okay, something is seriously broken here...
I am using Active Model Serializer and Pundit for my Rails 5 JSONAPI server and Ember for my frontend application.
I have User
model and Pundit policy for User model which prevent non-authors from viewing unpublished stories and chapters.
At the moment, I am seeing a weird problem which goes like this:
1. UserA creates StoryA, and two published chapters Chapter1 and Chapter2
2. UserA then creates two unpublished chapters Chapter3 and Chapter4
3. UserA logouts
4. UserB logins
5. UserB views the same story created by UserA
6. Server policy kicks in and scope the results to only published chapters since UserB isn't the author.
7. * An SQL DELETE query is sent to delete the two unpublished stories for some odd reason.
Here's some screenshot:
UserA creates 2 published stories and 2 unpublished stories
Database record shows 4 stories belong to Mount Targon story
UserA logs out and UserB logs in, views Mount Targon story
(As you can see, UserB only sees the two published chapters which is correct but...)
The unpublished chapters are deleted from the database for some odd reason
Looking at the Rails console, I see the DELETE query during a ChaptersController#show
CRUD action:
Started GET "/stories/16" for 127.0.0.1 at 2017-11-05 17:02:53 +0800
Processing by StoriesController#show as JSON
Parameters: {"id"=>"16"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 2], ["LIMIT", 1]]
Story Load (0.1ms) SELECT "stories".* FROM "stories" WHERE "stories"."id" = ? LIMIT ? [["id", 16], ["LIMIT", 1]]
Chapter Load (0.3ms) SELECT "chapters".* FROM "chapters" INNER JOIN "stories" ON "stories"."id" = "chapters"."story_id" INNER JOIN "users" ON "users"."id" = "stories"."user_id" WHERE "chapters"."story_id" = ? AND ((stories.published = 't' AND chapters.published = 't') OR stories.user_id = 2) [["story_id", 16]]
Chapter Load (0.1ms) SELECT "chapters".* FROM "chapters" WHERE "chapters"."story_id" = ? [["story_id", 16]]
(0.1ms) begin transaction
Started GET "/chapters/26" for 127.0.0.1 at 2017-11-05 17:02:53 +0800
SQL (0.3ms) DELETE FROM "chapters" WHERE "chapters"."id" = ? [["id", 32]]
Started GET "/chapters/27" for 127.0.0.1 at 2017-11-05 17:02:53 +0800
Processing by ChaptersController#show as JSON
SQL (0.1ms) DELETE FROM "chapters" WHERE "chapters"."id" = ? [["id", 33]]
Processing by ChaptersController#show as JSON
Parameters: {"id"=>"26"}
(2.1ms) commit transaction
Parameters: {"id"=>"27"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 2], ["LIMIT", 1]]
[active_model_serializers] User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 2], ["LIMIT", 1]]
Chapter Load (0.1ms) SELECT "chapters".* FROM "chapters" WHERE "chapters"."id" = ? LIMIT ? [["id", 26], ["LIMIT", 1]]
[active_model_serializers] Story Load (0.4ms) SELECT "stories".* FROM "stories" WHERE "stories"."user_id" = ? [["user_id", 1]]
Chapter Load (0.2ms) SELECT "chapters".* FROM "chapters" WHERE "chapters"."id" = ? LIMIT ? [["id", 27], ["LIMIT", 1]]
Started GET "/chapters/32" for 127.0.0.1 at 2017-11-05 17:02:53 +0800
Started GET "/chapters/33" for 127.0.0.1 at 2017-11-05 17:02:53 +0800
Story Load (0.2ms) SELECT "stories".* FROM "stories" WHERE "stories"."id" = ? LIMIT ? [["id", 16], ["LIMIT", 1]]
[active_model_serializers] Rendered StorySerializer with ActiveModelSerializers::Adapter::JsonApi (22.64ms)
Story Load (0.1ms) SELECT "stories".* FROM "stories" WHERE "stories"."id" = ? LIMIT ? [["id", 16], ["LIMIT", 1]]
Processing by ChaptersController#show as JSON
Processing by ChaptersController#show as JSON
[active_model_serializers] Rendered ChapterSerializer with ActiveModelSerializers::Adapter::JsonApi (0.82ms)
Completed 200 OK in 43ms (Views: 27.1ms | ActiveRecord: 3.9ms)
My ChaptersController show action does not even have the word "delete" or "destroy" in it...so how does the record get deleted?
# CHAPTERS CONTROLLER
def show
chapter = Chapter.find_by(id: params[:id])
if chapter.present?
authorize chapter
render json: chapter, status: :ok
else
skip_authorization
render json: { error: "Chapter not found" }, status: :not_found
end
end
My Chapter Policy show method:
# CHAPTER PUNDIT POLICY
def show?
(@record.published? && @record.story.published?) || (@record.story.user == @user)
end
My StoriesController Show action looks like:
# STORIES CONTROLLER
def show
story = Story.find_by(id: params[:id])
if story.present?
authorize story
story.chapters = policy_scope(story.chapters)
render json: story, include: [:user, :chapters], status: :ok
else
skip_authorization
render json: { errors: "Story not found" }, status: :not_found
end
end
I thought it might be Ember doing some funny extra query behind the scenes but I use Postman Mac application to test viewing the story and sure enough, the unpublished chapters are deleted without going through Ember at all. It's happening server side for some odd reason =/
Any ideas?
Aucun commentaire:
Enregistrer un commentaire