rails map.resources with has_many:through不起作用?

时间:2008-11-11 21:02:26

标签: ruby-on-rails resources map has-many

我有三个(相关的)模型,如下所示:

class User < ActiveRecord::Base
  has_many :posts
  has_many :comments
  has_many :comments_received, :through => :posts, :source => :comments
end

class Post < ActiveRecord::Base
  belongs_to :user
  has_many :comments
end

class Comment < ActiveRecord::Base
  belongs_to :user
  belongs_to :post
end

我希望能够引用带有路线的comments_received的所有user - 让我们说这是批量批准所有帖子的评论。 (请注意,您也可以comments获取user,但用户无法对自己的帖子发表评论,因此commentspostmap.resources :users, :has_many => [:posts, :comments, :comments_received] 不同且互相排斥的)。从逻辑上讲,这应该适用于:

user_posts_path
user_comments_path
user_comments_received_path

这应该给我

的路线
_

前两个工作,最后一个不工作。我试过没有comments_received中的http://some_domain.com/users/123/comments_received 无效。我希望得到一个像

这样的网址
map.resources :users do |user|
  user.resources :comments
  user.resources :posts, :has_many => :comments
end

我也试过嵌套它,但也许我做错了。在那种情况下,我认为地图将是:

http://some_domain.com/users/123/posts/comments

然后网址可能是:

comments

也许这是正确的方法,但我的语法错了?

我是否以错误的方式思考这个问题?对我而言,我应该能够将所有{{1}}的页面添加到用户的所有帖子中,这似乎是合理的。

感谢您的帮助!

3 个答案:

答案 0 :(得分:2)

尽管deinfe资源和模型关系的语法类似,但您不应该误以为资源映射到模型。阅读David Black has to say

您遇到的问题是您正在生成的路线。使用嵌套语法如下:

map.resources :users do |user|
  user.resources :posts
  user.resources :comments
  user.resources :comments_received
end

然后运行'rake routes',给我(在其他东西之中!):

                       users GET /users                              {:action=>"index", :controller=>"users"}
                  user_posts GET /users/:user_id/posts               {:action=>"index", :controller=>"posts"}
               user_comments GET /users/:user_id/comments            {:action=>"index", :controller=>"comments"}
user_comments_received_index GET /users/:user_id/comments_received   {:action=>"index", :controller=>"comments_received"}

因此看起来rails正在将comments_index添加到comments_received路由的末尾。我承认我不知道为什么(与其他评论路线冲突有什么关系?)但它解释了你的问题。

更好的替代方法可能是在评论资源上定义集合操作,如下所示:

map.resources :users do |user|
  user.resources :posts
  user.resources :comments, :collection => {:received => :get}
end

这将为您提供以下路线:

                 users GET /users                             {:action=>"index", :controller=>"users"}
            user_posts GET /users/:user_id/posts              {:action=>"index", :controller=>"posts"}
         user_comments GET /users/:user_id/comments           {:action=>"index", :controller=>"comments"} 
received_user_comments GET /users/:user_id/comments/received  {:action=>"received", :controller=>"comments"}

注意:收到的操作现在位于评论控制器上

答案 1 :(得分:0)

我必须承认,我对变量名称感到有些困惑,但首先,我很惊讶你的has_many:通过它所定义的所有方式工作。模型是否按预期运行,将路线搁置一秒?

其次,这就是变量名真正起作用的地方,路由对复数有一些依赖性,所以你的foos bar和bazs可能是问题的原因,或者可能隐藏了问题。无论如何,你绝对可以这样写:

map.resources :users do |user|
  user.resources :awards
  user.resources :contest_entries do |contest_entry|
    contest_entry.resources :awards
  end
end

我相信会给你:

user_path, user_awards_path, user_contest_entry_path, and user_contest_entry_awards_path.

我不确定这是否真的能回答你的问题,如果你把foo,bar和baz变成更接近实际情况的东西,这可能有助于更清楚地了解这里发生了什么。

答案 2 :(得分:0)

快速弄脏的解决方案是向用户控制器添加一个自定义方法(例如getusercomments),该方法将返回所有注释:

def getusercomments
@user = User.find(params[:id])
@comments = @user.posts.comments
end

然后将此方法添加到您的用户路线:

map.resources :users, :member => { :getusercomments => :get }

之后,您应该可以调用以下内容来获取用户的所有评论:

http://some_domain.com/users/123/getusercomments