Rails最佳实践:在单个控制器中处理多个关系

时间:2014-10-27 17:41:39

标签: ruby-on-rails ruby design-patterns ruby-on-rails-4

我的应用有照片模型。这些照片可以属于一些其他类,例如,主题,用户,标签。我希望能够根据不同的相关ID查询所有照片。我已经设置了嵌套资源,如:

resources :topics do
  resources :photos, only: ['index']
end

...

resources :users do
  resources :photos, only: ['index']
end

我想知道在控制器中处理这个问题的最佳做法是什么。 我最初的反应是写一个if / else块,但这感觉非常不重要。

if !params[:user_id].nil?
  # query based on user id
elsif !params[:topic_id].nil?
  # query based on topic id

etc.

我还讨论了设置控制器操作和路由到那些,例如user_photos#photos,topic_photos#photos。

或者设置一些新的控制器:UserPhotosController,TopicPhotosController

这些都不是正确的,我想知道是否有人有一些见解,或者是否有一个共同的设计模式来处理这样的事情。

这是一个Rails 4项目,顺便说一句。

3 个答案:

答案 0 :(得分:1)

如果您可以在一个控制器类中组合控制器逻辑,那么您应该这样做。我不明白为什么基于param值的选择应该是un-ruby。这似乎是正确的做法。

答案 1 :(得分:1)

你可以使用if语句。

你可以做的另一件事是你的if语句,然后把你的参数放到哈希中。然后,您可以将此哈希值传递给模型查找,以便在特定主题下查看特定用户的照片。

这方面的例子是这里的答案: https://stackoverflow.com/a/4480139/2589358

我发现这是一个很好的方法,因为它更容易管理,以后添加更多的params,而且它看起来更干净。

答案 2 :(得分:1)

首先,在Rails 4中,您可以使用concerns

concern :imageable do
  resources :photos, only: ['index']
end
resources :topics, concerns: :imageable
resources :users, concerns: :imageable

现在,我看到了解决这种情况的两种方法。

选项A :将if-else移动到只获得可成像的方法,即用户,标签,主题等。在您的PhotosController中:

rescue_from ActiveRecord::RecordNotFound, :with => :render_404

def index
  respond_with photos
end

private

def photos
  @photos ||= imageable ? imageable.photos : Photo.all
end

# Find and cache the imageable based on the id in params.
# Using find instead of find_by_id. This is to ensure ActiveRecord::RecordNotFound
# exception in the case of an invalid id passed, which be handled with render_404 method
def imageable
  @imageable ||= begin
    if id = params[:user_id]
      User.find(id)
    elsif id = params[:topic_id]
      Topic.find(id)
    end
  end
end

def render_404
  respond_to do |format|
    format.html { render template: 'errors/not_found', layout: 'layouts/application', status: 404 }
    format.all { render nothing: true, status: 404 }
  end
end

选项B :改变您的路线:

resources :photos, only: ['index'] do
  resources :topics
  resources :users
end

然后相应地更改TopicsControllerUsersController等,然后您无需创建UserPhotosControllerTopicPhotosController等。