问题描述
我正在构建一个 API,其中有一个名为 Studio 的模型。工作室有很多电影和很多系列,电影和系列有很多自己的角色。此外,一个角色可以出现在许多电影和/或许多系列中,并且属于一个工作室。 我现在已经弄清楚了所有模型关系表物流,但是我现在正在尝试做的事情,我想不出办法。
所以我的路线是这样设计的,所以我可以做一些类似 localhost:3000/api/v1/studios/1/characters 的事情 -> 这样我就可以显示所有工作室的 (studio_id: 1) 角色(来自所有电影和连续剧属于那个工作室)。 只需执行以下操作即可,这相当容易:
@characters = Character.where(studio_id:@studio.id)
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_serie
和 before_action :get_movie
,但它给了我一个错误,因为我从来没有同时获得 movie_id 和 serie_id,它是一个或另一个,所以它不能同时搜索。
来自角色的 POST 我只会从 localhost:3000/studios/1/characters
执行所以这不是问题,我只想能够从 localhost:3000/studios/1/movies/1/characters
和 localhost:3000/studios/1/seriees/1/characters
获取
我希望我没有说太多,你能理解我。如果您认为我解决这个问题的方式不对,请告诉我,因为我正在学习中,任何建议都非常有价值。
解决方法
我怀疑您是否真的想将这些资源嵌套更深一层:
经验法则:资源的嵌套深度不应超过 1 级。集合可能需要由其父级限定范围,但特定成员始终可以通过 id 直接访问,并且不需要限定范围(除非 id 由于某种原因不是唯一的)。
- 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)
无法满足电影很可能包含工作室角色的子集而不是整个电影世界的要求.相反,您需要一个连接电影和角色的连接表。