在我的Rails 4应用程序中,我有以下模型:
class Location < ActiveRecord::Base
has_many :location_parking_locations
has_many :parking_locations, through: :location_parking_locations
end
class LocationParkingLocation < ActiveRecord::Base
belongs_to :location
belongs_to :parking_location
end
class ParkingLocation < ActiveRecord::Base
has_many :location_parking_locations
has_many :locations, through: :location_parking_locations
end
对路线/locations/1/parking_locations
的调用会返回位置= 1的停车位置集合。响应中的某些属性来自连接模型(location_parking_location
)。例如,响应中的一个parking_locations可能如下所示:
{
id: 1
name: 'Test Parking Location'
description: 'Test description for the parking location'
upvote_count: 10, <- this field comes from the join model
downvote_count: 8, <- this field comes from the join model
}
如果用户想要更新直接来自停车位置的属性,例如名称,我觉得他们应该能够通过将停车位置视为主要资源的端点来实现,而不必将其作为特定位置的子资源引用。例如,他们应该能够从端点/parking_locations/1
编辑或检索parking_location,而不是特定于某个位置。
在这种情况下,不应包含来自location_parking_location的字段,例如upvote_count
和downvote_count
。
是否存在允许此行为的某种设计模式?或者我应该以不同的方式思考这个问题?例如,也许在检索端点locations/1/parking_locations
时,我不应该返回parking_locations
的集合,而应该返回location_parking_locations
的集合,其中可以包含表示来自的属性的对象parking_location
。在这种情况下,端点是否应更改为locations/1/location_parking_locations
?例如,响应中的一个对象可能如下所示:
{
id: 9
upvote_count: 10,
downvote_count: 8,
parking_location: {
id: 1
name: 'Test Parking Location'
description: 'Test description for the parking location'
}
}
在这种情况下,有人会如何添加新的停车位?是否可以使用帖子到/parking_locations
端点?或者他们应该创建它并同时将其添加到某个位置,也许是通过发布到/locations/1/parking_locations
?
在这种情况下,如果有人想将现有停车位添加到某个位置怎么办?在这种情况下,他们可能应该投入/locations/1/parking_locations/{parking_location_id}
?
答案 0 :(得分:1)
您可以使用一些简单的路由和一个许可控制器使您的ParkingLocation
模型成为主要和子资源。首先,路由 - 除了已经将它作为Location
的子资源的位置之外,您还要在顶层声明它。
resources :locations do
resources :parking_locations
end
resources :parking_locations
如果您现在检查rake routes
,则会看到两组网址都连接到ParkingLocationsController
,一组设置为/parking_locations
,另一组设置为/locations/:location_id/parking_locations
。
您的控制器将始终收到包含params[:id]
ID的ParkingLocation
。如果您访问嵌套路由,它还会收到包含params[:location_id]
ID的Location
。任何表单提交等都将包含params[:parking_location]
,其中包含create / update / etc的其余属性。一个简单的控制器可能如下所示:
class ParkingLocationsController
def index
if params[:location_id]
location = Location.find(params[:location_id])
@parking_locations = location.parking_locations
else
@parking_locations = ParkingLocation.all
end
end
def show
@parking_location = ParkingLocation.find(params[:id])
end
# ...
end
注意index
的工作原理与location_id
参数来源无关:
/locations/1/parking_locations
/parking_locations?location_id=1
由于您的RESTful资源是ParkingLocation
,因此您应该在Location
中处理ParkingLocationsController#update
个添加内容。为简单起见,您的控制器不应关心路由是PUT /locations/:location_id/parking_locations/:id
还是PUT /parking_locations/:id
。 has_many
关联提供ParkingLocation#location_ids=
,您可以按照自己喜欢的方式收集并传入控制器。您的update
操作看起来一如既往:
def update
@parking_location = ParkingLocation.find(params[:id])
if @parking_location.update(params[:parking_location])
redirect_to @parking_location
else
render :edit
end
end
此类请求会在Location
1
上设置2
s ParkingLocation
和3
:
PUT https://your.server/parking_locations/3?parking_location[location_ids[]]=1&parking_location[location_ids[]]=2
如果你想追加Location
,你需要做一些编码来自己处理。如果您想在Location
表单中创建ParkingLocation
(反之亦然),则需要查看Rails的nested form功能。