Rails 3 add GET action to RESTful controller - ruby-on-rails

I have a controller with the 7 RESTful actions plus an additional 'current' action, which returns the first active foo record:
class FooController < ApplicationController
def current
#user = User.find(params[:user_id])
#foo = #user.foos.where(:active => true).first
#use the Show View
respond_to do |format|
format.html { render :template => '/foos/show' }
end
end
#RESTful actions
...
end
The Foo Model :belongs_to the User Model and the User Model :has_many Foos.
If I structure the routes as such:
resources :users do
resources :foos do
member do
get :current
end
end
end
The resulting route is '/users/:user_id/foos/:id'. I don't want to specify the foo :id, obviously.
I've also tried:
map.current_user_foo '/users/:user_id/current_foo', :controller => 'foos', :action => 'current'
resources :users do
resources :foos
end
The resulting route is more like I would expect: '/users/:user_id/current_foo'.
When I try to use this route, I get an error that reads:
ActiveRecord::RecordNotFound in FoosController#current
Couldn't find Foo without an ID
edit
When I move the current action to the application controller, everything works as expected. The named route must be conflicting with the resource routing.
/edit
What am I missing? Is there a better approach for the routing?

I think you want to define current on the collection, not the member (the member is what is adding the :id).
try this.
resources :users do
resources :foos do
collection do
get :current
end
end
end
Which should give you a route like this:
current_user_foos GET /users/:user_id/foos/current(.:format) {:controller=>"foos", :action=>"current"}
Also map isn't used anymore in the RC, it will give you a deprecation warning.

Related

Issue with routes not calling the correct page

So I always thought routes was straightforward but it clearly isn't. I want my page to show data.html.erb but it keeps on showing show.html.erb. These are my only two views in the user folder
My controller is:
class UserController < ApplicationController
def data
render :json => User.including_relationships
end
end
and my routes.rb is:
Rails.application.routes.draw do
get 'users/:data' => 'users#data'
resources :user
end
I always seem to get the show.html.erb page instead of the data.html.erb. Im sure there's something easy to fix here but what?
The : before data in your route denotes a variable, try
Rails.application.routes.draw do
get 'users/data' => 'users#data'
resources :user
end

Rails: Have I over-engineered this quiz and results page?

Recently I've been trying to get a quiz page directing to a results page (and, with thanks to StanBoyet, I think I've finally managed it).
I have a User model and controller, and log in (using Devise) is all working fine. I have a QuizAnswers model and controller and all the tables present on the database. I also have a ResultsController.
Here is my routes.rb (note the resources):
Rails.application.routes.draw do
devise_for :users
root :to => 'home#index'
get "elearning" => "home#elearning"
get "howitworks" => "home#howitworks"
get "leadershipstyles" => "home#leadershipstyles"
get "whattypeofleader" => "quizzes#new"
get "showmetheskills" => "home#showmetheskills"
get "safeguarding" => "home#safeguarding"
get "toolsforthejob" => "home#toolsforthejob"
get "whatnext" => "home#whatnext"
get "congratulations" => "home#congratulations"
get "teamwork" => "home#teamwork"
get "facilitation" => "home#facilitation"
get "planning" => "home#planning"
get "communication" => "home#communication"
resources :quizzes
resources :results
resources :quiz_answers
resources :users do
resources :posts
end
end
In my quiz form, I pass form_for #quiz_answers (made accessible by the QuizAnswers#new action):
def new
#user = current_user
#quiz_answer = current_user.quiz_answers.build
end
(I have also tried, as an alternative, #quiz_answer = QuizAnswer.new)
When I click submit, the QuizAnswers#create action is triggered, which looks like this:
def create
redirect_to results_path
end
Which (rake routes tells me) points to results#index (ResultsController#index action) which I have set up like this:
def index
# in order to access all the results in our view...
#results = QuizAnswer.find(current_user.id)
end
When I click submit though, I'm getting the error:
Couldn't find QuizAnswer with 'id'=35
I have two questions:
How do I set up my new QuizAnswers with a reference to the id of the current_user? (QuizAnswers has a user_id attribute, as well as the usual id attribute).
Secondly, is this all horribly over-engineered or is this just 'the Rails way'? (If I'm doing it wrong, feel free to explain how I should do it 'right').
This line is very strange:
#results = QuizAnswer.find(current_user.id)
You need to change it to
#results = QuizAnswer.where(user_id: current_user.id)
#or
#results = current_user.quiz_answers

Testing a general controller action using rspec

Here's how my routes look like:
/article/:id/:action {:root=>"article", :controller=>"article/article", :title=>"Article"}
Here's how my controller looks like:
# app/controllers/article/article_controller.rb
class ArticleController < ApplicationController
def save_tags
# code here
end
end
I want to test the save_tags action so I write my spec like this:
describe ArticleController do
context 'saving tags' do
post :save_tags, tag_id => 123, article_id => 1234
# tests here
end
end
But when I run this spec, I get the error
ActionController::RoutingError ...
No route matches {:controller=>"article/article", :action=>"save_tags"}
I think the issue is the save_tags action is a general controller action, ie. there's no /article/:id/save_tags in routes. What's the best way to test this controller action?
You're spot on. The issue is that you're looking for a route which doesn't have :id in it, but you don't have one. You'll need to pass a parameter to the post :save_tags of :id, and given the above question, I believe it is what you are calling article_id.
Therefore, try changing your test to:
describe ArticleController do
context 'saving tags' do
post :save_tags, tag_id => 123, id => 1234
# tests here
end
end
Update
Rails might be getting confused because you're using :action in your route and I believe action is either a reserved word or a word that Rails treats as special. Maybe try changing your routes to:
/article/:id/:method_name {:root=>"article", :controller=>"article/article", :title=>"Article"}
And your test to:
describe ArticleController do
context 'saving tags' do
post :save_tags, { :tag_id => 123, :article_id => 1234, :method_name => "save_tags" }
# tests here
end
end
You need a route to map to your controller actions
post '/article/:id/save_tags'
should work, or consider using resources helper to build your routes
# creates the routes new, create, edit, update, show, destroy, index
resources :articles
# you can exclude any you do not want
resources :articles, except: [:destroy]
# add additional routes that require an article in the member block
resources :articles do
member do
post 'save_tags'
end
end
# add additional routes that do NOT require an article in the collection block
resources :articles do
collection do
post 'publish_all'
end
end

How do I add a route which maps to a slug url generated by the stringex gem in ruby on rails 3.1?

It seems simple, in my model I have:
class CustomerAccount < ActiveRecord::Base
acts_as_url :name
def to_param
url # or whatever you set :url_attribute to
end
end
And in my controller, I have:
class CustomerAccountsController < ApplicationController
def show # dashboard for account, set as current account
#account = CustomerAccount.find_by_url params[:id]
no_permission_redirect if !#account.has_valid_user?(current_user)
set_current_account(#account)
#latest_contacts = Contact.latest_contacts(current_account)
end
end
What's currently in the routes.rb is:
resources :customer_accounts, :path => :customer_accounts.url do
member do
get 'disabled'
post 'update_billing'
end
end
That gives me the following error when I try to generate data via rake db:seed, or at least I assume the entry in routes is what's doing it.
undefined method `url' for :customer_accounts:Symbol
So what do I need to do to get the route set up? What I'd like is http://0.0.0.0/customeraccountname to map to the view for the customer account page.
UPDATE:
Here is the code that ended up working in routes.rb, which I discovered after looking at the examples in the answer below:
resources :customer_accounts, :path => '/:id' do
root :action => "show"
member do
get 'disabled'
post 'update_billing'
end
end
If you want to set it up so you have a route like you show, do this:
get '/:id', :to => "customer_accounts#show"
If you want the disabled and update_billing actions underneath this:
get '/:id/disabled', :to => "customer_accounts#disabled"
post '/:id/update_billing', :to => "customer_accounts#update_billing"
Alternatively (and much neater):
scope '/:id' do
controller "customer_accounts" do
root :action => "show"
get 'disabled'
get 'update_billing'
end
end

Resourceful Routes helpers _path and _url dont work

I am trying to redirect user to show_city_url or show_city_path but i get an exception that they are both undefined.In the city controller i have three actions show,like, and dislike. unlike_city_path and like_city_path works but show_city_path doesnt.Also when i put this in all_cities action redirect_to :controller=>"city",:action=>"show" works.What am i doing wrong?Thank you.
class HomeController < ApplicationController
def all-cities
redirect_to show_city_url
end
end
In the Routes
resources :city do
member do
post :like
post :dislike
get :show
end
end
according to your comments:
resources :cities, :controller => 'city' do
collection do
get :show, :as => :show
end
member do
post :like
post :dislike
end
end
now you can call show_cities_url and you'll land in the show action of your CityController.
PS: Following the Rails' convention makes your life easier ;)
RoR Guide: Rails Routing from the Outside In

Resources