I have an issue on the Learn Rails by Example book Chapter 7 where at the end of the chapter I get these error messages in the rspec spec
1) UsersController should have the right title Failure/Error: get :show, :id => #user ActionController::RoutingError: No route matches {:id=>nil, :controller=>"users", :action=>"show"} # ./spec/controllers/users_controller_spec.rb:36:in `block (2 levels) in '
2) UsersController should include the user's name Failure/Error: get :show, :id => #user ActionController::RoutingError: No route matches {:id=>nil, :controller=>"users", :action=>"show"} # ./spec/controllers/users_controller_spec.rb:41:in `block (2 levels) in '
3) UsersController should have a profile image Failure/Error: get :show, :id => #user ActionController::RoutingError: No route matches {:id=>nil, :controller=>"users", :action=>"show"} # ./spec/controllers/users_controller_spec.rb:46:in `block (2 levels) in '
Below is all relevant code that I have done,
spec/controllers/users_controller_spec.rb
it "should have the right title" do
get :show, :id => #user
response.should have_selector("title", :content => #user.name)
end
it "should include the user's name" do
get :show, :id => #user
response.should have_selectori("h1", :content => #user.name)
end
it "should have a profile image" do
get :show, :id => #user
response.should have_selector("h1>img", :class => "gravatar")
end
end
app/controllers/Users_controller.rb
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
#title = #user.name
end
app/helpers/users_helper.rb
module UsersHelper
def gravatar_for(user, options = { :size => 50 })
gravatar_image_tag(user.email.downcase, :alt => user.name,
:class => 'gravatar',
:gravatar => options)
end
end
app/views/users/show.html.erb
<%= #user.name %>, <%= #user.email %>
<table class="profile" summary="Profile Information">
<tr>
<td class="main">
<h1>
<%= gravatar_for #user %>
<%= #user.name %>
</h1>
</td>
<td class="sidebar round">
<strong>Name</strong> <%= #user.name %><br />
<strong>URL</strong> <%= link_to user_path(#user), #user %>
</td>
</tr>
</table>
spec/factories.rb
Factory.define :user do |user|
user.name "Michael Hartl"
user.email "mhartl#example.com"
user.password "foobar"
user.password_confirmation "foobar"
end
I think you needed
get :show, :id => #user.id
or even just
get :show, :id => '1'
Instead you were using the entire object as a parameter.
This strongly indicates you didn't set up the #user instance variable in before block for these tests. I would say that was for certain if I could see the whole test, but it certainly looks like it.
Related
I'm new to rails, and developing first application gets hard because you know things, but you don't know how to do them.
I set my registration form in a box which comes out like a popup using "fancy-box" jquery.
When some user fails to sign up, I want the page to remain in the box with validation errors,
and when he signs up correctly I want to redirect him in the home page, but I can't do this:
My controller which overrides devise methods:
def setup
#society = Society.new
end
# GET /resource/sign_up
def new
super
end
# POST /resource
def create
build_resource
if resource.save
if resource.active_for_authentication?
set_flash_message :notice, :signed_up if is_navigational_format?
sign_in(resource_name, resource)
respond_with resource, :location => after_sign_up_path_for(resource)
else
set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_navigational_format?
expire_session_data_after_sign_in!
respond_with resource, :location => after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
render action: new
end
end
protected
def after_sign_up_path_for(resource)
'/vetrina/index' #my homepage
end
and the form:
<%= simple_form_for #society, :html => { :class => 'form-horizontal' } do |f| %>
<fieldset>
#all the inputs are here
<div class="form-actions">
<%= f.submit nil, :class => 'btn btn-primary' %>
<%= link_to 'Cancel', "#", :class => 'btn' %>
</div>
</fieldset>
Any help?
When I go to the path: /genre/new in my application I get this error:
myapp/app/views/genre/_form.html.erb where line #1 raised:
undefined method `genres_path' for #<#<Class:0x007fdcb39edcb0>:0x007fdcb39e8080>
However when I go to /genre/:id/edit the _form.html.erb file renders without error and the record is updated with no problems.
My new.html.erb and edit.html.erb files call <%= render 'form' %> and my _form.html.erb file has:
<%= form_for(#genre) do |f| %>
<%= f.label :title %> <br /> <%= f.text_field :title %>
<%= f.label :desc %> <br /> <%= f.text_field :desc %>
<%= f.submit %>
<% end %>
In genre_controller.rb my 'new' and 'edit' actions are as follows:
def new
#genre = Genre.new
current_user.authorize! :create, #genre # cancan authorization
respond_to do |format|
format.html # new.html.erb
format.json { render json: #genre }
end
end
def edit
#genre = Genre.find(params[:id])
current_user.authorize! :update, #genre # cancan authorization
end
I've run a search in my codebase for the string "genres" and the only place it occurs is in the logs, so I'm sure this is not a typo in my code.
My guess is that Rails routing system correctly pluralizes "genre" to "genre", but form_for (or a dependency) is creating the pluralization "genres", but only when the parameter passed to it is empty or "new".
Given the error is around 'genres_path', I tried various combinations of the following in my routes.rb file, but they didn't solve the problem:
match "/genres" => "genre#index", :as => :genre
match "/genres/:id(.:format)" => "genre#show", :as => :genre
match "/genre" => "genre#index", :as => :genres
match "/genre/:id(.:format)" => "genre#show", :as => :genres
Any thoughts on how I can work around this?
EDIT: Here are the routes generated by the resources :genre statement in my routes.rb file:
genre_index GET /genre(.:format) {:action=>"index", :controller=>"genre"}
POST /genre(.:format) {:action=>"create", :controller=>"genre"}
new_genre GET /genre/new(.:format) {:action=>"new", :controller=>"genre"}
edit_genre GET /genre/:id/edit(.:format) {:action=>"edit", :controller=>"genre"}
genre GET /genre/:id(.:format) {:action=>"show", :controller=>"genre"}
PUT /genre/:id(.:format) {:action=>"update", :controller=>"genre"}
DELETE /genre/:id(.:format) {:action=>"destroy", :controller=>"genre"}
on new.html.erb try
<%= form_for(#genre, :url => genre_path, :method => :post) do |f| %>
assuming you have your route setup as a resource - resources :genre
also this will not work on edit.html.erb
http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_for
Update:
this is the one we are interested in
POST /genre(.:format) {:action=>"create", :controller=>"genre"}
try this
<%= form_for(#genre, :url => {:action=>"create", :controller=>"genre"}, :method => :post) do |f| %>
am trying to confirm a user account without using the built in devise confirmations controller but i happen to get the following error "uninitialized constant Confirmations Controller". Below is my confirmations controller class.
class ConfirmationsController < Devise::ConfirmationsController
def show
#user = User.find_by_confirmation_token(params[:confirmation_token])
if !#user.present?
render_with_scope :new
end
end
def confirm_account
#user = User.find(params[:user][:confirmation_token])
if #user.update_attributes(params[:user]) and #user.has_password?
#user = User.confirm_by_token(#user.confirmation_token)
flash[:notice] = "Hi " + #user.first_name + " your email has been verified. You can now start shopping and recommending other users to your supplier networks."
redirect_to #user
else
render :action => "show"
end
end
end
And in my routes.rb file i have the following:
devise_for :users, :controllers => { :confirmations => "confirmations" } do
match "confirm_account", :to => "confirmations#confirm_account"
end
And finally i have the following partial:
<p>Welcome <%= #user.first_name %>,</p><br/>
<%= form_for(resource, :url => confirm_account_path) do |f| %>
<%= f.label :email %>
<%= #user.email %>
<%= f.hidden_field :confirmation_token %>
<%= f.submit 'Confirm Account' %>
<p>Thank you for joining. Before you can purchase any item from your supplier or shared network, you will need to confirm your account first. Please follow the link below in order to confirm your account.</p>
<p><%= link_to 'Confirm my account', confirmation_url(#resource, :confirmation_token => #resource.confirmation_token) %></p><br/>
<p>Yours faithfully.</p>
<%end%>
Devise is can be easily modified for your needs. Here is a similar topic, which may be helpful for you:
Override devise registrations controller
Through other posts on SO I've learned that my sign-up process using a nested model form is flawed in that I create a new User, then redirect to create its Profile. Here is the process:
user = User.new
user.email = ...
user.password = ...
user.profile = Profile.new
user.profile.first_name = ...
...
user.profile.save
user.save
It seems as if one solution is to initiate the profile method from within the UsersController create(?) action, so that I POST to both models(?) then redirect to a page with a form to fill out the rest of the profile.
But I'm not entirely sure how to do that, as I am new to programming/Rails. So can anyone give me guidance on how to introduce the Profile method within the UsersController? I gave it a go but don't think it's correct. Code for both Users/ProfilesController below:
User:
def new
#user = User.new
#user.profile = Profile.new
end
def index
#user = User.all
end
def create
#user = User.new(params[:user])
if #user.profile.save
redirect_to profile_new_path, :notice => 'User successfully added.'
else
render :action => 'new'
end
end
Profile:
def new
#user.profile = Profile.new
end
def create
#profile = Profile.new(params[:profile])
if #profile.save
redirect_to profile_path, :notice => 'User successfully added.'
else
render :action => 'new'
end
end
Routes.rb:
match '/signup' => 'profiles#new', :as => "signup"
get "signup" => "profiles#new", :as => "signup"
root :to => 'users#new'
resources :users
resources :profiles
My nested model form (the relevant parts):
<%= form_for(:user, :url => { :action => :create }, :html => {:id => 'homepage'}) do |f| %>
<%= f.text_field :email, :size=> 13, :id => "user[email]" %>
<%= f.fields_for :profile do |f| %>
<% end%>
<% end %>
If anyone could help me I'd greatly appreciate it.
You should have something like this in your models:
class User < ActiveRecord::Base
has_one :profile
accepts_nested_attributes_for :profile
end
class Profile < ActiveRecord::Base
belongs_to :user
end
...of course all backed up with proper migrations. Then while building up a form you can use fields_for helper. Here is slightly modified example from docs:
<%= form_for #user do |user_form| %>
Email: <%= user_form.text_field :email %>
<%= user_form.fields_for :profile do |profile_fields| %>
First Name: <%= profile_fields.text_field :first_name %>
<% end %>
<% end %>
And update your user and his profile in the controller in one go, thanks to accepts_nested_attributes_for :profile declaration in your model.
I've been reading over this resource as well as this post to try to understand Routes more (currently learning programming/Rails by doing) but am wondering how I can fix the error I'm getting, which is No route matches {:controller=>"profiles", :action=>"show"}.
I get the error working my way through a Rails 3 sign-up process using nested model forms. The sign-up process, as follows:
user = User.new
user.email = ""
user.password = ""
user.profile = Profile.new
user.profile.save
user.save
The sign-up process starts at the homepage with the following form:
<%= form_for :user, :url => signup_path, :html => {:id => 'homepage'} do |f| %>
<div>
...
</div>
<%= f.fields_for :profile do |f| %>
<% end %>
<% end %>
Then the process goes to fill in the profile, then redirect to the new User's profile after this form is completed:
<%= form_for :profile, :html => { :multipart => true } do |f| %>
<div>
...
</div>
<%= f.fields_for :user do |f| %>
<% end %>
<% end %>
I have accepts_nested_attributes_for :user and :profile in their respective models.
My rails server it gives me a bit more detail:
ActionController::RoutingError (No route matches {:controller=>"profile.save", :action=>"show"}):
app/controllers/profiles_controller.rb:15:in `create'
So in my ProfilesController in 'create':
def create
#profile = Profile.new(params[:profile])
if #profile.save
redirect_to profile_path, :notice => 'User successfully added.'
else
render :action => 'new'
end
end
Seems clear that the issue is in profile_path, so my Routes.rb:
post "/signup" => "profiles#create", :as => "signup"
match "skip/signup", :to => "info#signupskip"
match "skip/profiles/new", :to => "profiles#newskip"
root :to => "users#create"
Can anyone help shed light on what I'm doing wrong/missing in my Routes.rb file?
The redirect path should contain the specific profile to redirect to:
if #profile.save
redirect_to profile_path(#profile), :notice => 'User successfully added.'
else
.....
Also the routes should include this line:
get "/profiles/:id" => "profiles#show", as => "profile"