Rails Route Configuration - ruby-on-rails-3

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

Rails 3 routes - URL name?

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.

Routing with id and handle in Rails

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)

rails caching: expire_action in another namespace

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.

Testing non-resource actions in Ruby on Rails

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 :-)

Defining :id in routes to be something other than id in rails 3

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.