所以我有一个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
作为我的网址。
这是我的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
操作?
编辑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 e.g:
# 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<%=render partial: "shared/color", locals: {post: post.status }%>"><%= post.status.try(:upcase) %></span>
我试过这样做:
<span class="post-status status label<%=render partial: "shared/color", locals: {post: post.status }%>"><%= link_to post.status.try(:upcase), post.status.path %></span>
但这给了我一个undefined method path
错误。
在正常情况下,我只是进行字符串插值,Ruby会渲染当前字符串。鉴于Ruby应该解析这条路径,我怀疑这会起作用。
那么如何让该视图根据confirmed_path, corroborated_path, unconfirmed_path
动态自动生成post.status
?
答案 0 :(得分:1)
如你所见,你在路线上迷路了。此处调用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
匹配,然后与get 'posts/:friendly_id', to: 'posts#show'
匹配。
现在,即使您将所有get
路由移至顶部,也不会将其转移到您稍后可能要定义的其他方法,因为所有posts/unconfirmed
,posts/confirmed
等都将与get 'posts/:id' => redirect("/%{id}")
匹配,并将重定向为/confirmed
,/unconfirmed
等。
推荐的方法是为单个路线设置单独的方法,因为将来您可能希望确认的帖子与确认的帖子具有不同的行为。为此,您的路线将如下所示:
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 e.g:
# 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
并确保status
中有PostsController
方法:
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