向现有控制器添加一个操作(Ruby on Rails)

36

我刚接触Ruby on Rails,已经完成了博客教程

现在我正在尝试向控制器添加一个名为“start”的额外操作。

def start
end

我添加了一个视图页 "app/views/posts/start.html.erb",其中只包含简单的 html。

当我访问 /posts/start 时,会出现以下错误。

ActiveRecord::RecordNotFound in PostsController#show 
Couldn't find Post with ID=start

我理解这个错误,show操作正在执行,而start不是一个有效的ID。为什么start操作没有被执行?我是否错过了MVC架构或配置中的某些部分?
以下是我的posts_controller.rb文件:
class PostsController < ApplicationController

  # GET /posts/start
  def start
  end

  # GET /posts
  # GET /posts.xml
  def index
    @posts = Post.find(:all)
    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @posts }
    end
  end

  # GET /posts/1
  # GET /posts/1.xml
  def show
    @post = Post.find(params[:id])
    respond_to do |format|
      format.html # show.html.erb
      format.xml  { render :xml => @post }
    end
  end

end

是的,我已经重新启动服务器,并尝试使用 Mongrel 和 Webrick。


请重新标记...“on”不应该是一个标签。 - andHapp
7个回答

45
你犯的错误其实相当常见。基本上,Rails会自动映射你的脚手架URL。因此,当你创建了Posts的脚手架时,Rails正在为它映射URL路由。其中一个路由是查看单个帖子的URL:/posts/(post_id)。
所以,当你输入URL /posts/start时,Rails认为你是在说“嘿,给我ID = start的帖子”。因此,Rails抱怨找不到这个ID的帖子。
修复这个问题的一种快速方法是确保你的config/routes.rb在脚手架路由之前拥有start动作的路由。
# Route for start action
map.connect '/posts/start', :controller => 'posts', :action => 'start'
# Default mapping of routes for the scaffold
map.resources :posts

无论如何,希望能帮到你。


1
谢谢您的解释,我需要更多地了解路由。 - Mark
4
在理解 RoR(Ruby on Rails) 中路由工作原理时,最有帮助的一点是记住它们从上到下逐个进行评估。因此,通常最好将更具体的路由放在通用(全捕获)路由之前,这是一种最佳实践。 - David
我使用了match '/pages/action', :controller => 'pages', :action => 'action'这个代码,它运行成功了。 - Ira Herman

33
Rails 4.x 版本使用以下代码:
get '/posts/start', :controller => 'posts', :action => 'start'

在Rails 3.x中使用:

match '/posts/start', :controller => 'posts', :action => 'start'

相比之下

map.connect '/posts/start', :controller => 'posts', :action => 'start'

它解决了我的问题。


26

你的路由设置不允许该路由。假设你正在使用默认脚手架,请将这行代码放在 config/routes.rb 文件中 map.resources :posts 行之前:

map.connect "posts/:action", :controller => 'posts', :action => /[a-z]+/i

:action的正则表达式仅限于a-z(以避免捕获类似/posts/1这样的内容)。如果您的新操作需要下划线或数字,则可以进行改进。


8
如果您使用的是Rails 3.0.3,请尝试以下方法:
在您的route.rb文件中:
 resource :posts do
   collection do
     get 'start'
   end
 end

这可能会有所帮助


2

我想说,有时Rails在开发环境下的路由缓存会出现问题。

尝试重启Rails服务器可能会有帮助。当遇到这个错误时,这个方法对我来说已经有效无数次了。


1

这个有效:

map.resource :post, :collection => { :my_action => :get}

在Rails 3中,collection选项将"collection"=>{"my_action"=>:get}添加到GET参数中。 - rxgx

0
我在 routes.rb 文件中找到了解决我的问题的方法。
map.resource :post

我添加了一个集合参数,所以它保持不变:

map.resource :post, :collection => { :my_action => :get}

2
在Rails 3中,这将向GET参数添加"collection"=>{"my_action"=>:get} - rxgx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接