简体   繁体   中英

Rails Pundit policy_scope on render json include fields

Continuing my previous question at: Active Model Serializer and Pundit deleting records during a Show CRUD action

I have a situation where a User should not be able to view another user's unpublished chapters belonging to a Story an author created.

Eg If UserA creates a story called Targon and provides 2 published chapters and 2 unpublished chapters, then UserB should only see published chapters for Targon story.

Normally with Pundit policy scoping, it scopes the index CRUD action.

What I need to scope however, are Chapters belonging to a Story during the render json line:

render json: story, include: [:user, :chapters], status: :ok

I have tried:

# ---------------------------------------------------------------------------
# ActiveRecord auto-save will kick in and delete all unpublished chapters
# ---------------------------------------------------------------------------
story.chapters = policy_scope(story.chapters)

render json: story, include: [:user, :chapters], status: :ok

According to https://gist.github.com/demisx/9896113 (has_many section) the above code will delete all the unpublished chapters belonging to Targon when I reassign story.chapters :

story.chapters = policy_scope(story.chapters) # BAD

I am hoping there is some way I can do something like this :

render json: story, include: [:user, policy_scope(:chapters)], status: :ok

At the moment, without scoping the story.chapters any users who fetch for Story with ID 16 (Targon) will get back JSONAPI:

{
    "data": {
        "id": "16",
        "type": "stories",
        "attributes": {
            "title": "Mount Targon",
            "summary": "Mount Targon is the mightiest peak in Runeterra, a towering peak of sun-baked rock amid a range of summits unmatched in scale anywhere else in the world. Located far from civilization, Mount Targon is utterly remote and all but impossible to reach save by the most determined seeker. Many legends cling to Mount Targon, and, like any place of myth, it is a beacon to dreamers, madmen and questors of adventure. Some of these brave souls attempt to scale the impossible mountain, perhaps seeking wisdom or enlightenment, perhaps chasing glory or some soul-deep yearning to witness its summit. The ascent is all but impossible, and those hardy few who somehow survive to reach the top almost never speak of what they have seen. Some return with a haunted, empty look in their eyes, others changed beyond all recognition, imbued by an Aspect of unearthly, inhuman power with a destiny few mortals can comprehend.",
            "published": true,
            "published-date": "2017-11-02T10:35:33.184Z",
            "created-at": "2017-11-02T10:35:33.184Z",
            "updated-at": "2017-11-04T07:35:04.083Z",
            "cover": {
                "url": "http://res.cloudinary.com/chewedon/image/upload/v1509780931/c8ubn3tfivxziyxwynsa.png",
                "standard": {
                    "url": "http://res.cloudinary.com/chewedon/image/upload/c_fill,g_north,h_300,w_200/c8ubn3tfivxziyxwynsa.png"
                }
            }
        },
        "relationships": {
            "user": {
                "data": {
                    "id": "1",
                    "type": "users"
                }
            },
            "chapters": {
                "data": [{
                    "id": "26",
                    "type": "chapters"
                }, {
                    "id": "27",
                    "type": "chapters"
                }, {
                    "id": "37",
                    "type": "chapters"
                }, {
                    "id": "38",
                    "type": "chapters"
                }]
            }
        }
    },
    "included": [{
        "id": "1",
        "type": "users",
        "attributes": {
            "username": "Chewedon",
            "photo": {
                "url": "http://res.cloudinary.com/chewedon/image/upload/v1509857442/nx1tqlcdxrhz6r3kjx87.jpg",
                "standard": {
                    "url": "http://res.cloudinary.com/chewedon/image/upload/c_fill,g_north,h_150,w_150/nx1tqlcdxrhz6r3kjx87.jpg"
                }
            }
        },
        "relationships": {
            "stories": {
                "data": [{
                    "id": "1",
                    "type": "stories"
                }, {
                    "id": "2",
                    "type": "stories"
                }, {
                    "id": "3",
                    "type": "stories"
                }, {
                    "id": "4",
                    "type": "stories"
                }, {
                    "id": "5",
                    "type": "stories"
                }, {
                    "id": "6",
                    "type": "stories"
                }, {
                    "id": "8",
                    "type": "stories"
                }, {
                    "id": "9",
                    "type": "stories"
                }, {
                    "id": "10",
                    "type": "stories"
                }, {
                    "id": "11",
                    "type": "stories"
                }, {
                    "id": "12",
                    "type": "stories"
                }, {
                    "id": "13",
                    "type": "stories"
                }, {
                    "id": "14",
                    "type": "stories"
                }, {
                    "id": "15",
                    "type": "stories"
                }, {
                    "id": "16",
                    "type": "stories"
                }]
            }
        }
    }]
}

Here in the relationship section, chapters 37 and 38 are unpublished, leading to a 403 Forbidden on my Ember frontend.

Ideally the server should have scoped out these before returning the records but due to the bug I described above and in my previous Stackoverflow question, I am stuck on how to scope included fields with Pundit.

Any ideas?

Thanks to user oowowaee from previous linked question, who suggested overriding the Story serializer's chapters field (which I didn't know you could do that), the code is working now and the records don't get deleted from database.

class StorySerializer < ActiveModel::Serializer
  include Pundit

  attributes :id, :title, :summary, :published, :published_date, :created_at, :updated_at, :cover

  belongs_to :user
  has_many :chapters

  # ------------------------------------------------------------------------
  # Note: need to use 'object.chapters' not 'self.chapters` below.
  # ------------------------------------------------------------------------
  def chapters
    policy_scope(object.chapters)
  end
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM