如何直接创建到范围的链接/路由?

所以我有一个Post模型,它有以下范围:

  scope :unconfirmed, -> { where( status: "unconfirmed") } scope :corroborated, -> { where( status: "corroborated") } scope :confirmed, -> { where( status: "confirmed") } 

我想要做的是当有人去posts/confirmed它显示所有确定的范围。

这样做最优雅的方法是什么? 另外,如何在routes.rb为每个范围创建路径?

编辑1

我知道一种方法是在我的posts控制器中为每个可枚举的范围创建一个动作(即unconfirmed等)。

但我宁愿在我的索引操作中完成所有这些 – 所以我正在渲染并使用我的索引视图。

我试过在我的Post#Index这样做:

 if params[:unconfirmed] @posts = Post.published.unconfirmed end 

但这只是给我一个路由错误。

这是错误:

 Started GET "/unconfirmed" for 127.0.0.1 at 2014-10-27 02:29:51 -0500 Processing by PostsController#show as HTML Parameters: {"id"=>"unconfirmed"} Post Load (3.0ms) SELECT "posts".* FROM "posts" WHERE "posts"."publication_status" = 1 AND "posts"."slug" = 'unconfirmed' ORDER BY "posts"."id" ASC LIMIT 1 Post Load (1.7ms) SELECT "posts".* FROM "posts" INNER JOIN "friendly_id_slugs" ON "friendly_id_slugs"."sluggable_id" = "posts"."id" AND "friendly_id_slugs"."sluggable_type" = 'Post' WHERE "posts"."publication_status" = 1 AND ("friendly_id_slugs"."sluggable_type" = 'Post' AND "friendly_id_slugs"."slug" = 'unconfirmed') ORDER BY "posts"."id" ASC LIMIT 1 Completed 404 Not Found in 28ms ActiveRecord::RecordNotFound - ActiveRecord::RecordNotFound: friendly_id (5.0.4) lib/friendly_id/finder_methods.rb:23:in `find' () myapp/controllers/posts_controller.rb:78:in `set_post' 

set_post方法是:

  private # Use callbacks to share common setup or constraints between actions. def set_post @post = Post.published.find(params[:id]) end 

我正在使用friendly_id作为我的url。

这是我的routes.rb

  get 'posts/:id' => redirect("/%{id}") get '/:friendly_id', to: 'posts#show' get 'posts/:friendly_id', to: 'posts#show' 

编辑2

我仍然收到此错误。 我相信是这样的,因为每当我尝试执行/confirmed或任何其他状态时,这就是我的日志的样子:

 Started GET "/confirmed" for 127.0.0.1 at 2014-10-31 18:28:55 -0500 ActiveRecord::SchemaMigration Load (2.2ms) SELECT "schema_migrations".* FROM "schema_migrations" Processing by PostsController#show as HTML Parameters: {"friendly_id"=>"confirmed"} Completed 404 Not Found in 58ms 

遵循此路由规则:

  get '/:friendly_id', to: 'posts#show' get 'posts/:friendly_id', to: 'posts#show' 

即使我在路由文件的末尾为我的resources post推荐的路由规则,它仍然会这样做,例如:

  resources :posts do collection do get 'confirmed' => 'posts#index', status: 'confirmed' get 'unconfirmed' => 'posts#index', status: 'unconfirmed' get 'corroborated' => 'posts#index', status: 'corroborated' end end root to: "posts#index" 

如何让状态路由不被重定向到posts#index action?

编辑3

查看我的完整routes.rb

 Rails.application.routes.draw do %w[privacy terms].each do |page| get page, controller: 'info', action: page end resources :locations devise_for :users, :path_names => { :sign_up => "register", :sign_in => "login", :sign_out => "logout", :settings => "settings" }, :controllers => { :confirmations => "confirmations" } devise_scope :user do get "login", :to => "devise/sessions#new" get "register", :to => "devise/registrations#new" get "settings", :to => "devise/registrations#edit" delete "logout", :to => "devise/sessions#destroy" end resources :posts do collection do get 'confirmed' => 'posts#status', status: 'confirmed' get 'unconfirmed' => 'posts#status', status: 'unconfirmed' get 'corroborated' => 'posts#status', status: 'corroborated' end end get 'posts/:id' => redirect("/%{id}") get '/:friendly_id', to: 'posts#show' get 'posts/:friendly_id', to: 'posts#show' # This supports legacy URLs eg: # http://www.example.com/rbt/26766-algaj-pays-tribute-to-the-honourable-roger-clarke.html get '/rbt/:name', to: redirect {|path_params, _| "/#{path_params[:name].gsub(/^\d+\-/, '')}" } get ':name', to: 'posts#show' root to: "posts#index" end 

编辑4

最后一点是问题的原始前提,如何创建指向新创建路径的链接。

棘手的一点是我想根据状态动态创建link_path。

例如,作为新路由规则的结果,我现在有confirmed_path, corroborated_path, unconfirmed_path

但是,我在我的视图中显示它们是这样的:

 <span class="post-status status label"> 

我试过这样做:

 <span class="post-status status label"> 

但这给了我一个undefined method path错误。

在一个普通的例子中,我只是做字符串插值,Ruby会渲染当前的字符串。 鉴于Ruby应该解析这条路径,我怀疑这会起作用。

那么如何让该视图根据post.status动态自动生成confirmed_path, corroborated_path, unconfirmed_path

如你所见,你在路线上迷路了。 在这里调用posts/confirmed将在posts#show而不是你的posts#index方法代替。 原因是动作包从上到下给出了路由的优先级,因为你的路由定义如下:

 resources 'posts' get 'posts/:id' => redirect("/%{id}") get '/:friendly_id', to: 'posts#show' get 'posts/:friendly_id', to: 'posts#show' 

所有posts/unconfirmedposts/confirmed等将永远不会进入索引方法,因为它将与posts#show #show匹配,然后与get 'posts/:friendly_id', to: 'posts#show'匹配get 'posts/:friendly_id', to: 'posts#show'

现在,即使您将所有get路线移至顶部,也不会将其转移到您可能希望稍后定义的其他方法,因为所有posts/unconfirmedposts/confirmed等将与get 'posts/:id' => redirect("/%{id}")匹配get 'posts/:id' => redirect("/%{id}")并将被重定向为/confirmed/unconfirmed等。

推荐的方法是为各个路线设置单独的方法,因为将来您可能希望确认的post与确认的post具有不同的行为。 为此,您的路线将如下所示:

 resources :posts do collection do get 'confirmed' get 'unconfirmed' get 'corroborated' end end 

运行$ rake routes|grep posts会给出:

  confirmed_posts GET /posts/confirmed(.:format) posts#confirmed unconfirmed_posts GET /posts/unconfirmed(.:format) posts#unconfirmed corroborated_posts GET /posts/corroborated(.:format) posts#corroborated posts GET /posts(.:format) posts#index POST /posts(.:format) posts#create new_post GET /posts/new(.:format) posts#new edit_post GET /posts/:id/edit(.:format) posts#edit post GET /posts/:id(.:format) posts#show PATCH /posts/:id(.:format) posts#update PUT /posts/:id(.:format) posts#update DELETE /posts/:id(.:format) posts#destroy 

然后你创建单独的方法,即confirmedunconfirmedcorroborated等。

但是,您始终可以将所有这些路径指向这样的路径(不建议这样做):

 resources :posts do collection do get 'confirmed' => 'posts#status', status: 'confirmed' get 'unconfirmed' => 'posts#status', status: 'unconfirmed' get 'corroborated' => 'posts#status', status: 'corroborated' end end 

然后在你的PostsController

 def status @posts = Post.published.where(status: params[:status]) end 

更新 :将您的routes.rb更改为此 –

 Rails.application.routes.draw do %w[privacy terms].each do |page| get page, controller: 'info', action: page end resources :locations devise_for :users, :path_names => { :sign_up => "register", :sign_in => "login", :sign_out => "logout", :settings => "settings" }, :controllers => { :confirmations => "confirmations" } devise_scope :user do get "login", :to => "devise/sessions#new" get "register", :to => "devise/registrations#new" get "settings", :to => "devise/registrations#edit" delete "logout", :to => "devise/sessions#destroy" end resources :posts get '/confirmed' => 'posts#status', status: 'confirmed', as: :confirmed get '/unconfirmed' => 'posts#status', status: 'unconfirmed', as: :unconfirmed get '/corroborated' => 'posts#status', status: 'corroborated', as: :corroborated get 'posts/:id' => redirect("/%{id}") get '/:friendly_id', to: 'posts#show' get 'posts/:friendly_id', to: 'posts#show' # This supports legacy URLs eg: # http://www.example.com/rbt/26766-algaj-pays-tribute-to-the-honourable-roger-clarke.html get '/rbt/:name', to: redirect {|path_params, _| "/#{path_params[:name].gsub(/^\d+\-/, '')}" } get ':name', to: 'posts#show' root to: "posts#index" end 

并确保你的PostsControllerstatus方法:

 def status # your code for fetching posts goes here! render text: params[:status] # this is to show an example that `status` is set properly end