过滤 rails API json 输出中的嵌套属性

Filtering nested attributes in rails API json output

我正在构建一个 API,其中我有一个名为 Studio 的模型。工作室有很多电影和很多系列,电影和系列有很多自己的角色。此外,一个角色可以出现在多部电影 and/or 多个系列中,并且属于一个工作室。 我现在已经弄清楚了所有模型关系表逻辑,但我现在想做的是,我想不出办法。

所以我的路线是这样设计的,所以我可以做类似 localhost:3000/api/v1/studios/1/characters 的事情 -> 这样我就可以显示工作室的所有 (studio_id: 1) 个角色(来自所有属于该工作室的电影和系列)。 只需执行以下操作即可相当容易:

@characters = Character.where(studio_id:@studio.id)

在我的 CharactersController 中,我有

def get_studio
    @studio = Studio.find(params[:studio_id])
end

现在我正在尝试设计物流,这样我就可以做到localhost:3000/api/v1/studios/1/seriees/1/characters 并且只从该特定系列中获取角色。 localhost:3000/api/v1/studios/1/movies/1/characters应该也是有效的。

我试过了

def get_movie
    @movie = Movie.find(params[:movie_id])
end`

def get_serie
    @serie = Seriee.find(params[:seriee_id])
end

在我的 CharactersController 中,在代码的最开头有 before_action :get_seriebefore_action :get_movie,但它给了我一个错误,因为我从来没有同时得到 movie_id 和seriee_id,非此即彼,无法同时搜索。

来自角色的 POST 我只会从 localhost:3000/studios/1/characters 做,所以这不是问题,我只想能够从 localhost:3000/studios/1/movies/1/characterslocalhost:3000/studios/1/seriees/1/characters

我希望我没有啰嗦太多,你能理解我。如果您认为我解决这个问题的方法不对,请告诉我,因为我只是在学习,任何建议都将非常有价值。

我怀疑您是否真的想将这些资源嵌套得超过一层:

Rule of thumb: resources should never be nested more than 1 level deep. A collection may need to be scoped by its parent, but a specific member can always be accessed directly by an id, and shouldn’t need scoping (unless the id is not unique, for some reason).
- Jamis Buck

鉴于此处的域,您必须指定工作室才能获取给定电影的角色是没有意义的。嵌套在 REST 中的目标是通过使两个实体成为 URL 结构的一部分来明确两个实体之间的关系——不要过于明确。

当涉及到 url 生成之类的东西时,过多的嵌套会导致一些非常复杂的代码 - 我的意思是你真的想写吗?

 url_for [:ap1, :v1, studio, movie, :characters]

您可以使用 shallow: true 选项解决这些问题:

resources :studios do
  resources :movies, shallow: :true do
    resources :characters
  end
end

或者避免“俄罗斯娃娃”调用 resources:

resources :studios do
  resources :movies, only: [:new, :create]
end

resources :movies, only: [:show, :update, :destroy] do
  resources :characters, only: [:create, :index]
end

您也确实应该使用关联来获取嵌套项。

class CharactersController
  before_action :set_movie, only: [:index, :create]

  # GET /api/v1/movies/1/characters.json
  def index
    @characters = @movie.characters
  end


  private

  def set_movie
    @movie = Movie.find(params[:movie_id])
  end
end

一般来说,像 Character.where(studio_id: @studio.id) 这样的代码应该避免,因为它会泄露关系的实现细节。您的控制器不需要知道角色和工作室之间的关系 - 它只知道 movie 有一个名为 characters.

的方法

而且我真的不想在这里详细介绍您的建模,但是 Character.where(studio_id: @studio.id) 不适用于电影很可能包含工作室角色的子集 - 而不是全部角色的要求电影宇宙。相反,您需要一个连接电影和角色的联接 table。