轨道3 - 处理嵌套的资源查询,在控制器的最好方法? [英] Rails 3 - Best way to handle nested resource queries in your controllers?

查看:143
本文介绍了轨道3 - 处理嵌套的资源查询,在控制器的最好方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果有一件事我已经了解Rails 3的是,如果我有一个很难做的事情,我可能做错了。所以我寻求帮助。

If there's one thing I've learned about Rails 3 is if I'm having a hard time doing something, I'm probably doing it wrong. So I'm looking for help.

我这是在一个多对多的关系有关的几个模型。

I have a few models which are related in a many to many relationship.

我能够创建在模型中的关联没有问题。我的问题在于如何建立控制器,这些关系的工作。我会试着举个例子,如果你没有看到我要去这一点。

I am able to create the associations in the models without a problem. My problem lies in how to build the controllers to work with these relationships. I'll try and give an example if you don't see where I'm going with this.

例如...

class Account < ActiveRecord::Base
    has_many :locations
end

class Contact < ActiveRecord::Base
    has_many :locations
end

class Location < ActiveRecord::Base
    has_and_belongs_to_many :accounts
    has_and_belongs_to_many :contacts
end

让我们说我有以上车型。这将是我的资源...

Let's say I have the above models. This would be my resources...

resources :accounts do
    resources :locations
end

resources :contacts do
    resources :locations
end

resources :locations do
    resources :accounts
    resources :contacts
end

因此​​,只要保持这种缩短了一下,比方说我要一个账户的所有位置的列表。以上航线将presumably是账号/ 1 /位置。因此,在位置#指数登陆我。

So just to keep this shortened a bit, let's say I want a list of all locations for an account. The above routes would presumably be account/1/locations. Thus landing me at locations#index.

我希望我没有搞砸了我的例子在这一点上,但什么是打造这个动作了,因为它确实有多个职位的最佳途径......至少一个帐户,接触的位置,和所有位置。

Hopefully I haven't screwed up my example at this point but what's the best way to build this action out as it really has multiple jobs... at a minimum the locations for an account, contact, and all locations.

所以,我结束了这样的事情...

So I end up with something like this...

class LocationController < ApplicationController
    def index
        if params[:account_id]
            @locations = Location.find_all_by_account_id(params[:account_id])
        elsif params[:contact_id]
            @locations = Location.find_all_by_contact_id(params[:account_id])
        else
            @locations = Location.all
        end

        respond_with @locations
    end
end

更新#1:为了澄清,因为我得到了一些答案,建议我改变我的模型关系。我正与一个遗留系统,我可以在这一点不会改变的关系。它最终是我的目标,以清理数据库和关系,但现在我不能。所以,我需要找到一个解决方案,这个配置工作。

Update #1: To clarify, as I am getting some answers that suggest I change my Model relationships. I am working with a legacy system in which I can NOT change the relationships at this point. It is ultimately my goal to clean up the database and the relationships but for now I can not. So I need to find a solution that works with this configuration.

推荐答案

您目前的做法是不干燥,而且会给你头疼,如果说,例如,你想强加于指数其他范围;例如分页,排序,或者通过搜索字段。

Your current approach is not DRY, and would give you a headache if say, for example, you wanted to impose additional scopes on the index; e.g. pagination, ordering, or searching by a field.

考虑一个替代方案:请注意如何你如果/ ELSIF / else条件基本上是刚刚发现的查找范围发送查找来?为什么不动的责任,不只是一个方法?因此,简化了您的操作,并删除冗余code。

Consider an alternative: Note how your if/elsif/else conditional essentially is just finding the lookup scope to send find to? Why not move that responsibility to a method that does just that? Thus simplifying your actions and removing redundant code.

def index
  respond_with collection
end

def show
  respond_with resource
end

protected

# the collection, note you could apply other scopes here easily and in one place,
# like pagination, search, order, and so on.
def collection
  @locations ||= association.all
  #@locations ||= association.where(:foo => 'bar').paginate(:page => params[:page])
end

# note that show/edit/update would use the same association to find the resource
# rather than the collection
def resource
  @location ||= association.find(params[:id])
end

# if a parent exists grab it's locations association, else simply Location
def association
  parent ? parent.locations : Location
end

# Find and cache the parent based on the id in params. (This could stand a refactor)
#
# Note the use of find versue find_by_id.  This is to ensure a record_not_found
# exception in the case of a bogus id passed, which you would handle by rescuing
# with 404, or whatever.
def parent
  @parent ||= begin
    if id = params[:account_id]
      Account.find(id)
    elsif id = params[:contact_id]
      Contact.find(id)
    end
  end
end

inherited_resources 是用于清洁处理这样的情况有很大的宝石。撰稿何Valim(钢轨)。我的相信的它应该与HABTM,但老实说,我不,如果我曾经尝试过积极的。

inherited_resources is a great gem for cleanly handling scenarios like this. Written by Jose Valim (of Rails). I believe it should work with HABTM, but honestly I'm not positive if I've ever tried it.

以上〔实施例本质上是如何inherited_resources作品,但主要是它的工作原理它的魔力在幕后,你只覆盖方法,如果你需要。如果它与HABTM(我认为它应该),你可以写你的电流控制器是这样的:

The above exmaple is essentially how inherited_resources works, but mostly it works its magic behind the scenes, and you only overwrite methods if you need to. If it works with HABTM (I think it should), you could write your current controller something like this:

class LocationController < InheritedResources::Base
  belongs_to :contact, :account, :polymorphic => true, :optional => true
end

这篇关于轨道3 - 处理嵌套的资源查询,在控制器的最好方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆