I have a series of items I would wish to edit. When editing the current format of my URL appears as such:
http://mysite/items <---- Lists the items
http://mysite/items/1/ <------ more detailed view of items
http://mysite/items/1/edit <----- Ability to edit the item
The routing configuration I would like to try and apply to my structure would like something like this:
http://mysite/items <---- Lists the items
http://mysite/item <---- Detailed view of the item by sending the item ID as POST data
http://mysite/item/edit <---- Edits the item by sending the item ID as POST data
Is this strictly an event of the rails route configuration or do I have to configure the links in the items page to structure the URL specifically.
Try this:
#config/routes.rb
#assuming your actions are in ItemsController
match 'items' => 'items#index', :via => :get
match 'item' => 'items#show', :via => :post
match 'item/edit' => 'items#edit', :via => :post
Be aware this is more for legacy applications/URLs as Rails convention follows RESTful mapping. Further info in the routing guide.
Related
I'm not sure how to change a route's URL. As the :as parameter does something else now than in Rails 2
This only changes the route helpers to faq_path, but the url still goes to /faqs. I want the url to be singular.
resources :faqs, :as => "faq" do
collection { post :sort }
end
Doing a single match (below) won't really be the same
match "/faq" => "faqs#index"
If you want change all the URLs related to the faqs resources you can do the following:
resources :faqs, :path => 'faq'
See docs for further information.
I'm trying to set up rails to use both the ID and the Handle (which is just an URL safe version of the title) of a blog post in the route.
match '/articles/:id/:handle', :to => 'articles#show'
resources :articles
This works, of course -- but I can't seem to set up the to_param method in the model os the longer URL -- with the handle attached, is the default.
This doesn't work (not that I really expected it to):
def to_param
"#{id}/#{handle}"
end
I get a No route matches {:action=>"edit", :controller=>"articles", error. I also tried just using the handle, but then Rails generates links to the resource just using the handle and not the ID. I know I can do it with a - in stead of a /, but I prefer the /. Any way to make this work? If I have to add some extra paremeters to my link_to helpers, that's okay.
Did you try to pass a Hash to link_to?
link_to "Link", {:id => #article.id, :handle => #article.handle}
Update
You have to modify your routes:
match '/articles/:id/:handle', :to => 'articles#show', :as => :article_with_handle
and use the following helper to generate the link:
link_to "Link", article_with_handle_path(:id => #article.id, :handle => #article.handle)
You can override the helper to simplify things:
def article_with_handle_path(article)
super(:id => article.id, :handle => article.handle)
end
and use it like this:
link_to "Link", article_with_handle_path(#article)
Okay, here's what I did to remove the query string problem from the answer above:
Changed the route to this:
match '/articles/:id/:handle' => 'articles#show', :as => :handle
Removed the to_param method from the model and then generated the link like this:
link_to 'Show', handle_path(:handle => article.handle, :id => article.id) %>
That works, but could be condensed, obviously, with the helper above. Just change the one line to: args[1] = handle_path(:id => args[1].id, :handle => args[1].handle)
My application is using a namespace for administrative purposes. I recently tried to start using action caching however I ran into some problems trying to expire the cache using expire_action. Basically I have a index action in my default namespace newsposts controller that is cached using action caching like this:
class NewspostsController < ApplicationController
caches_action :index, :layout => false
def index
#posts = Newspost.includes(:author).order("created_at DESC").limit(5)
end
end
This caches the view under views/host/newsposts.
The default namespace has no actions for modifying data, they are all in my admin namespace. In my Admin::NewspostsController I am trying to expire this cache in the create action like this:
expire_action(:controller => 'newsposts', :action => 'index')
however this will expire a cache file located under views/host/admin/newsposts. Obviously it can not work since im in the admin namespace and rails is (rightfully) looking to expire cache for this namespace. Sadly I can not pass a namespace parameter to the axpire_action method, so how can i expire the action cache in another namespace?
after some more digging I finally found the solution. It's a bit hinted in the url_for method:
In particular, a leading slash ensures no namespace is assumed. Thus, while url_for :controller => 'users' may resolve to Admin::UsersController if the current controller lives under that module, url_for :controller => '/users' ensures you link to ::UsersController no matter what.
So basically,
expire_action(:controller => '/newsposts', :action => 'index')
Will expire in the default namespace, and
expire_action(:controller => 'admin/newsposts', :action => 'index')
in the admin namespace (when in default).
RailsCast
One additional note I learned, if you want to expire a specific format, such as XML, JSON, etc., just
expire_action(:controller => '/newsposts', :action => 'index', :format => 'xml')
or whatever format you want. It look me a while to figure out.
I've added the following in my config/routes.rb file:
match 'login' => 'sessions#new'
match 'logout' => 'sessions#destroy'
match 'auth/:provider/callback' => 'sessions#create'
match 'auth/failure' => 'sessions#new'
match 'sessions/delegate' => 'sessions#delegate'
This allows me to have my own custom login form that authenticates through OmniAuth and an OpenID provider in this case. The routes and the code works well, but I have a problem with writing functional tests for the SessionsController.
Testing the new action works well:
test "show login form when requesting new session" do
get :new
assert_response :success
end
But testing the create action gives me an exception: ActionController::RoutingError: No route matches {:controller=>"sessions", :action=>"create"}
The code is like this:
test "create session adds logged in user" do
request.env['rack.auth'] = {:uid => auths(:one).open_id, :provider => 'open_id'}
post :create
# assert that create action did it's things here
end
I've tried to replace the post with a get but the result is the same.
Why is the one action found, and not the other?
Presumably it's getting confused because you're not supplying the :provider key from the match pattern. You might find it clearer to specify names for these non-resourceful routes, like:
match 'auth/:provider/callback' => 'sessions#create', as: 'callback'
This will allow you to post callback_path(provider: whatever) in your test, I think :-)
I am porting a Merb app to Rails 3. In Merb we could put an Identify block around a route to define how an :id route parameter was to be supplied, e.g.,
# this is a Merb route that I want to port to Rails 3 routing; I get everything except
# how to replicate the behavior of Merb's Identify block which doesn't require one to
# futz with overriding to_param on user; a user instance gets passed to the url builder
# ala url(:edit_password_reset, user) and this tells the router to use the
# reset_password_token method on user to supply the :id value for this one route
Identify User => :reset_password_token do
match("/reset-password/:id", :method => :get).to(:controller => "password_resets", :action => "edit").name(:edit_password_reset)
end
# and then later define more routes that use the user's id without a problem
# since to_param was not overridden on user; here I have already translated to
# Rails 3 and this works fine
controller :users do
get "/register", :action => "new", :as => "new_user"
get "/users", :action => "index", :as => "users"
get "/users/:id", :action => "show", :as => "show_user"
get "/users/:id/edit", :action => "edit", :as => "edit_user"
put "/users/:id", :action => "update", :as => "update_user"
post "/users", :action => "create", :as => "create_user"
end
In Rails, as in Merb, you can override to_param to provide an alternative id value for routes, but for a case where one time you want to use an id and another time you want to use a different method on the same object (as above), Identify is convenient. What is the Rails 3 equivalent? I looked through the Rails 3 source and tests and didn't see anything equivalent to Identify. Did I miss it?
I can refactor things and maybe should to not need it in this case, but still I would like to know if I missed something.
Thanks.
I came across the same problem; turns out the best way is to skip to_param entirely when calling a url or path. For instance:
# This will set params[:id] to #user.to_param
edit_password_reset_url(#user)
# This will set params[:id] to #user.reset_password_token
edit_password_reset_url(#user.reset_password_token)
In other words, to_param is only called when passing a record to the url helpers; if you pass it a string instead, it will just parse the string.