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

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

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 Custom Route Gets Confused on :id

I am trying to setup a custom route. However whenever I hit the beverage_locations/new page, it tries to send 'new' in the url as the :location_id in the index path.
route.rb
controller 'beverage_locations' do
get 'beverage_locations/:location_id' => 'beverage_locations#index'
get 'beverage_locations/new' => 'beverage_locations#new'
end
error
ActiveRecord::RecordNotFound in BeverageLocationsController#index
Couldn't find Location with id=new
any idea how to fix this?
Thanks!
Rails routes are matched in the order they are specified, so if you
have a resources :photos above a get 'photos/poll' the show action’s
route for the resources line will be matched before the get line. To
fix this, move the get line above the resources line so that it is
matched first.
From http://guides.rubyonrails.org/routing.html#crud-verbs-and-actions
A demo:
# beverage_locations_controller.rb
class BeverageLocationsController < ApplicationController
def index
render :text => params[:location_id]
end
def new
render :text => 'New method'
end
end
# config/routes.rb
Forfun::Application.routes.draw do
controller 'beverage_locations' do
get 'beverage_locations/new' => 'beverage_locations#new'
get 'beverage_locations/:location_id' => 'beverage_locations#index'
end
end
# http://localhost:3000/beverage_locations/1234 => 1234
# http://localhost:3000/beverage_locations/new => New method
You need to swap the order of the routes so that the new action has preference:
controller 'beverage_locations' do
get 'beverage_locations/new' => 'beverage_locations#new'
get 'beverage_locations/:location_id' => 'beverage_locations#index'
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

How to route to different actions depending on the request method in Rails?

As we all know, a simple
resources :meetings
will generate 7 actions for me. Two of these are index and create. A really cool thing about these two!: The URL for both is /meetings, but when I GET /meetings I am routed to the def index action and when I POST /meetings, I am routed to the def create action. Nice.
Now I want to do this:
resources :meetings do
member do
get 'scores'
post 'scores'
end
end
And, you guessed it!, I want them to route to different actions in MeetingsController: GETting /meetings/1/scores will route to def scores and POSTing to meetings/1/scores will route to def create_scores.
Try:
resources :meetings do
member do
get 'scores' => :scores
post 'scores' => :create_scores
end
end
I suppose you will be also interested in having named routes:
resources :meetings do
member do
get 'scores' => :scores, :as => 'scores_of'
post 'scores' => :create_scores, :as => 'create_scores_of'
end
end
Then you get scores_of_meeting_path and create_scores_of_meeting_path helpers.
Above may be DRYed more with:
get :scores, :as => 'scores_of'
Define the routes such as this:
resources :meetings do
member do
get 'scores', :action => "scores"
post 'scores', :action => "post_scores"
end
end
But it sounds to me like it would be much easier to create another controller to handle this, as scores to me feels like another resource entirely, even if they don't have their own model association.
Ha! Never underestimate the ability of asking a question well to lead you to its answer.
resources :meetings do
member do
get 'scores', :to => "meetings#scores"
post 'scores', :to => "meetings#create_scores"
end
end

Rails 3 add GET action to RESTful controller

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.

Resources