我很想获得一些我最近一直在处理的代码的输入。
我有一个模型,photos
,有时(但不总是)属于collection
。我有一个页面供用户管理集合,他们可以将任何未分配的照片添加到集合中或从集合中删除照片。
这是一个“编辑多个”情况,因此我创建了两个新的控制器操作:select
,它处理GET请求和视图,assign
处理来自复选框的PUT请求选择视图。
由于用户可以将照片添加到集合中或从集合中删除照片,因此我的assign
操作中包含一个条件,它看起来像这样:
def assign
@photos = Photo.find(params[:photo_ids])
case params[:assignment]
when 'add'
@photos.each do |p|
p.collection = @collection
p.save!
end
notice = "Photos added to collection."
when 'remove'
@photos.each do |p|
p.collection = nil
p.save!
end
notice = "Photos removed from collection."
end
redirect_to select_collection_photos_path(@collection), :notice => notice
end
这完全符合预期。但是,我觉得它很不舒服,它似乎不适合“Rails Way”。
其他Rails开发人员,当你遇到这种情况时,你会像我一样处理它吗?你会在两个控制器动作(即add_to_collection
和remove_from_collection
)之间拆分它,还是将它移动到模型中?如果你要将它移到模型中,那会是什么样的?
我很感激任何建议和反馈。谢谢!
答案 0 :(得分:2)
可能有几种不同的方法可以重构这一点,但最明显的方法似乎是将所有照片逻辑移动到Photo模型。即使这是你的照片控制器,它也不应该对照片模型了解太多。
我可能会在你的控制器中沿着这些方向做点什么:
def assign
Photo.update_collection(params, @collection)
redirect_to select_collection_photos_path(@collection), :notice => "Photo collection updated"
end
然后在你的照片模型中:
class Photo < ActiveRecord::Base
def self.update_collection(params, collection)
photos = Photo.find(params[:photo_ids])
case params[:assignment]
when 'add'
photos.each {|p| p.add_collection(collection) }
when 'remove'
photos.each {|p| p.remove_collection }
end
end
def add_collection(collection)
self.collection = collection
save!
end
def remove_collection
self.collection = nil
save!
end
end
将功能分解为更小的模型方法可以更轻松地进行单元测试,如果不是,则应该这样做:)
答案 1 :(得分:0)
这实际上是accepts_nested_attributes_for的主要候选者。
不要考虑控制器中的新操作,只要有可能,请坚持使用标准REST约定。除了花哨的UI显示内容(比如你的选择动作),我很少发现我需要偏离生成的scaffold_controller中存在的标准CRUD操作。
如果在Photo模型中设置accepts_nested_attributes_for:collection,则应该能够构建一个特殊的表单,将集合分配给照片。我不会在此处详细介绍完整的详细信息,而是指向http://railscasts.com/episodes/196-nested-model-form-part-1和http://railscasts.com/episodes/197-nested-model-form-part-2。在视图中,这将是更多的工作,但你会在更简单,易于测试的控制器和模型中走得更远。