如何直接创建到范围的链接/路由?
所以我有一个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/unconfirmed
, posts/confirmed
等将永远不会进入索引方法,因为它将与posts#show
#show匹配,然后与get 'posts/:friendly_id', to: 'posts#show'
匹配get 'posts/:friendly_id', to: 'posts#show'
。
现在,即使您将所有get
路线移至顶部,也不会将其转移到您可能希望稍后定义的其他方法,因为所有posts/unconfirmed
, posts/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
然后你创建单独的方法,即confirmed
, unconfirmed
, corroborated
等。
但是,您始终可以将所有这些路径指向这样的路径(不建议这样做):
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
并确保你的PostsController
有status
方法:
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